创建线程的方式
方法一,直接使用 Thread
// 构造方法的参数是给线程指定名字,推荐
Thread t1 = new Thread("t1") {
@Override
// run 方法内实现了要执行的任务
public void run() {
log.debug("hello");
}
};
t1.start();
方法二,使用 Runnable 配合 Thread
把【线程】和【任务】(要执行的代码)分开
- Thread 代表线程
- Runnable 可运行的任务(线程要执行的代码
// 创建任务对象
Runnable task2 = new Runnable() {
@Override
public void run() {
log.debug("hello");
}
};
// 参数1 是任务对象; 参数2 是线程名字,推荐
Thread t2 = new Thread(task2, "t2");
t2.start();
方法三,Callable
Runnable接口缺少一项功能就是,当线程终止时(即run()完成时),我们无法使线程返回结果。为了支持次功能,Java提供了Callable接口。
- 为了实现Runnable,需要实现不反悔任何内容的run()方法,而对于Callable接口,需要在完成时返回结果的Call()方法
- call()方法可以引发异常,而run()不行
- 为了实现Callable而必须重写call方法
Threadl类中的构造器是不能传Callable的,只能传Runnable
所以以下这种方式创建线程是不对的:
new Thread(new Callable(),"tt").start()
Thread只能
```java
new Thread(new Runnable(),"tt").start()
那必须找一个类,使其既和Runnable有关系,也和Callable有关系,,,FeatureTask,FeatureTask是Runnable实现类,同时它的构造器可以传Callable,这样就实现了Callable与Runnable的关联。
1、Callable 与Runnable的区别
1)Callable规定的方法是call(),Runnable规定的方法是run().
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的
(3)call方法可以抛出异常,run方法不可以
(4)运行Callable任务可以拿到一个Future对象,Future 表示异步计算的结果
2、Callable结合futureTask创建执行任务,把任务传到Thread中,然后启动任务的执行
public class CallableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask futureTaskTest = new FutureTask(new Callable() {
@Override
public Integer call() throws Exception {
System.out.println("callable1");
return 1024;
}
});
FutureTask futureTask = new FutureTask(()->{
System.out.println("callable2");
return 2048;
});
new Thread(futureTask,"t1").start();
while (!futureTask.isDone()){
System.out.println("通过isDone可以判断任务是否结束");
}
System.out.println("通过get方法可以获取任务的执行结果");
System.out.println(futureTask.get());
}
}
通过isDone可以判断任务是否结束
通过isDone可以判断任务是否结束
通过isDone可以判断任务是否结束
通过isDone可以判断任务是否结束
通过isDone可以判断任务是否结束
通过isDone可以判断任务是否结束
通过isDone可以判断任务是否结束
通过isDone可以判断任务是否结束
通过isDone可以判断任务是否结束
通过isDone可以判断任务是否结束
通过isDone可以判断任务是否结束
通过isDone可以判断任务是否结束
通过isDone可以判断任务是否结束
通过isDone可以判断任务是否结束
通过get方法可以获取任务的执行结果
2048
3**、FutureTask 的细节:**
- get方法的位置,一般放在最后一行,否则主线程会阻塞在get处等待其返回
public class CallableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask futureTask = new FutureTask(()->{
System.out.println("callable2");
Thread.sleep(10000);
return 2048;
});
System.out.println("任务启动:"+ System.currentTimeMillis());
new Thread(futureTask,"t1").start();
System.out.println(futureTask.get());
System.out.println("main线程结束:"+ System.currentTimeMillis());
}
}
任务启动:1657859321584
callable2
2048
main线程结束:1657859331587
public class CallableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask futureTask = new FutureTask(()->{
System.out.println("callable2");
Thread.sleep(10000);
return 2048;
});
System.out.println("任务启动:"+ System.currentTimeMillis());
new Thread(futureTask,"t1").start();
System.out.println("main线程结束:"+ System.currentTimeMillis());
System.out.println(futureTask.get());
}
}
任务启动:1657859359366
main线程结束:1657859359366
callable2
2048
- 任务只执行一次
下面启动了两个线程t1、t2执行任务,通过打印结果可以看出任务只执行了一次
public class CallableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask futureTask = new FutureTask(()->{
System.out.println("callable");
return 2048;
});
new Thread(futureTask,"t1").start();
new Thread(futureTask,"t2").start();
System.out.println(futureTask.get());
}
}
callable
2048