状态
线程生命周期不可逆:一旦进入 Runnable 状态就不能回到 New 状态;一旦被终止就不可能再有任何状态的变化。所以一个线程只能有一次 New 和 Terminated 状态,只有处于中间状态才可以相互转换。
创建
准确的讲,创建线程只有一种方式那就是构造Thread类而实现线程的执行单元有两种方式
实现Runnable接口的run方法,并把Runnable实例传给Thread类
实现 runnable 接口
public class MyRunnable implements Runnable {
@Override
public void run() {
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(50));
System.out.println("dddd");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
new Thread(new MyRunnable()).start();
new Thread(new MyRunnable()).start();
}
}
匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
}).start();
lambda表达式
Runnable race2 = () -> System.out.println("Hello world !");
new Thread(race2).start();
重写Thread的run方法(继承Thread类)
class demo extends Thread {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("---------------" + i);
}
}
}
new demo().start();
定时器
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println("dd");
}
},10,10);
Callable和Future
- Future接口定义了操作异步任务执行一些方法,如获取异步任务的执行结果、取消任务的执行、判断任务是否被取消、判断任务执行是否完毕等。
- Callable接口中定义了需要有返回的任务需要实现的方法
- Future是一个存储器,它存储了call这个任务的结果,而这个任务的执行时间是无法提前确定的
Runnable的缺陷
- 不能返回一个返回值
- 也不能抛出checked Exception
FutureTask
- FutureTask是一种包装器,可以把Callable转化成Future和Runnable,它同时实现二者的接口
- 所以它既可以作为Runnable被线程执行,又可以作为Future 得到Callable的返回值
- 把Callable实例当作参数,生成FutureTask的对象,然后把这个对象当作一个Runnable对象,用线程池或另起线程去执行这个Runnable对象,最后通过FutureTask获取刚才执行的结果
Callable<Integer> callable = () -> {
System.out.println("dd");
return 1;
};
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread thread = new Thread(futureTask);
thread.start();
Integer integer = futureTask.get();
System.out.println(integer);
future 方法
get
- 任务正常完成∶get方法会立刻返回结果
- 任务尚未完成(任务还没开始或进行中)∶get将阻塞并直到任务完成。
- 任务执行过程中抛出Exception∶get方法会抛出ExecutionException∶这里的抛出异常,是call执行时产生的那个异常,看到这个异常类型是java.util.concurrent.ExecutionException。不论call执行时抛出的异常类型是什么,最后get方法抛出的异常类型都是ExecutionException。
- 任务被取消∶get方法会抛出CancellationException
get(long timeout, TimeUnit unit)
- 如果call在规定时间内完成了任务,那么就会正常获取到返回值;而如果再指定时间内没有计算出结果,那么就会抛出TimeoutException
- 超时不获取,任务需取消
isDone()轮询
轮询的方式会耗费无谓的CPU资源,而且也不见得能及时地得到计算结果.
如果想要异步获取结果,通常都会以轮询的方式去获取结果 ,尽量不要阻塞
@Test
public void isDone() throws ExecutionException, InterruptedException {
FutureTask<String> futureTask = new FutureTask<>(() -> {
System.out.println("-----come in FutureTask");
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
return ""+ThreadLocalRandom.current().nextInt(100);
});
new Thread(futureTask,"t1").start();
System.out.println(Thread.currentThread().getName()+"\t"+"线程完成任务");
/**
* 用于阻塞式获取结果,如果想要异步获取结果,通常都会以轮询的方式去获取结果
*/
while(true)
{
if (futureTask.isDone())
{
System.out.println(futureTask.get());
break;
}
}
}
}
总结
- 不见不散
- 过时不候
- 轮询