Java编程思想之java多线程基础

并发“具有可论证的确定性,但是实际上具有不可确定性”

实现与创建线程

实现

1. 实现Runnable接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class LiftOff implements Runnable {
protected int countDown = 10;
private static int taskCount = 0;
private final int id = taskCount++;
public LiftOff() {
}
public LiftOff(int countDown) {
this.countDown = countDown;
}
public String status() {
return "#" + id + "(" + (countDown > 0 ? countDown : "LiftOff!") + "),";
}
@Override
public void run() {
// System.out.println(Thread.currentThread().getName());
while (countDown-- >0){
System.out.print(status());
Thread.yield();
}
System.out.println();
}
}

2. 继承Thread对象:重写run方法,自定义操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class SimpleThread extends Thread {
private int countDown = 5;
private static int threadCount = 0;
public SimpleThread() {
super(Integer.toString(++threadCount));
// 构造函数内启动线程不合理,可能会造成访问不稳定状态的对象
start();
}
@Override
public String toString() {
return "#"+getName()+"("+countDown+"),";
}
@Override
public void run() {
super.run();
while (true){
System.out.println(this);
if (--countDown == 0){
return;
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new SimpleThread();
}
}
}
  • 两种实现方法没什么区别,两者可以互相替换。
  • 如果使用实现Runnable的线程实现方法,可以继承另一个不同的类

开始线程

  • 使用Thread新建一个线程运行,
    将需要运行的Runnable对象作为Thread的构造参数
    new Thread(new LiftOff()).start
  • Runnable执行:在当前线程开始线程
    直接执行Runnable对象的run()方法
    new LiftOff().run();
  • Executor 启动任务的优选方法,可以实现线程启动的不同策略

Executor的使用方法

1
2
3
4
5
6
// 初始化,可以使用不同的Executor方法,实现不同的线程创建策略
ExecutorService exec = Executors.newCachedThreadPool();
// 执行Runnabale对象
exec.execute(new LiftOff());
// 关闭, 避免新任务提交给这个Executor,当前线程执行完调用shutdown()之前所有任务后,会尽快退出
exec.shutdown();
执行器类型
  • CachedThreadPool
    创建与所需数量相同的线程,然后在它回收线程时停止创建线程
  • SingleThreadExecutor
    单一线程执行器:将任务排队,序列化所有提交给它的任务,并会维护它自己(隐藏)的悬挂任务队列
  • FixedThreadPool
    一次性预先执行线程分配,可限制线程数量,可直接从池中获取线程

线程参数

1.优先级

Thread.currentThread().setPriority(priority);

  • priority有10个级别,但可移植的优先级设置只有:MAX_PRIORITY,MIN_PRIORITY,NORM_PRIORITY
  • 最好在run()方法中设置优先级

2.休眠与让步

  • sleep(),使任务中止指定时间
  • yield(),向计算机建议具有相同优先级的其他线程可以运行,但不能保证一定采纳

3.后台线程 线程启动前调用setDaemon()

  • 程序运行的时候在后台提供一种通用服务的线程
  • 当所有非后台线程结束时,程序也终止了,进程中的所有后台线程也会被杀死

4.返回值: 在任务完成时返回一个值

  • 通过Executor的submit()方法执行实现Callable接口的对象
  • Future对象得到返回结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class CallableDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
ArrayList<Future<String>> results = new ArrayList<>();
for (int i = 0; i < 10; i++) {
// 用executor的submit()方法执行Callable对象,返回一个Future对象,内容贮存在Future对象中
// 通过get()获取内容,isDone()方法判断Future是否已经完成,
results.add(executorService.submit(new TaskWithResult(i)));
}
for (Future<String> fs :
results) {
try {
System.out.println(fs.get());
} catch (InterruptedException e) {
e.printStackTrace();
return;
} catch (ExecutionException e) {
e.printStackTrace();
}finally {
executorService.shutdown();
}
}
}
}
class TaskWithResult implements Callable<String> {
private int id;
public TaskWithResult(int id) {
this.id = id;
}
@Override
public String call() throws Exception {
return "thread" +Thread.currentThread().getName()+","+
"result of TaskWithResult" + id;
}
}