目录
3、 Callable 接口和 ExecutorService
1、 Thread 类
通过 Thread 类创建线程:最常见的方式是继承 Thread
类,并重写其 run()
方法。
优缺点:这种方式比较简单;但不够灵活,且不能继承其他类。
2、Runnable接口
使用Runnable
接口是创建线程的另一种方式,它定义了一个 run()
方法,不像 Thread
类那样直接继承。可以将任务逻辑封装到一个 Runnable
对象中,再通过 Thread
来启动线程。
优点:
-
任务和线程的实现是分离的,可以复用任务代码。
-
可以继承其他类,因为不需要继承
Thread
类。
缺点:需要创建 Thread
对象来启动线程,稍显繁琐。
Runnable案例:
import java.util.concurrent.atomic.AtomicLong;
public class ThreadLearn {
//public static AtomicLong result = new AtomicLong(0); //Atomic方式
public static long result; //synchronized方式
public static void main(String[] args) throws InterruptedException {
int count = 10000;
Thread[] threads = new Thread[count];
//记录开始时间
long start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
MyThread myThread = new MyThread(100);
threads[i] = new Thread(myThread);
threads[i].start();
}
//等待所有线程结束
for (Thread thread : threads) {
thread.join();
}
System.out.println(result);
long end = System.currentTimeMillis();
System.out.println("耗时:"+(end - start)+"ms");
}
}
class MyThread implements Runnable {
private int count;
public MyThread(int count) {
this.count = count;
}
@Override
public void run() {
int sum = 0;
for (int i = 0; i <= count; i++) {
sum+=i;
}
//ThreadLearn.result.addAndGet(sum);//Atomic方式
synchronized (ThreadLearn.class) {
ThreadLearn.result+=sum;
}
System.out.println(sum);
}
}
3、 Callable 接口和 ExecutorService
Callable
接口是 Runnable
接口的扩展,它允许任务有返回值,并且可以抛出异常。通常与 ExecutorService
接口配合使用,能够更高效地管理线程池。
优点:
-
任务可以有返回值。
-
通过
ExecutorService
进行线程池管理,能更高效地复用线程。 -
可以抛出异常,
Future.get()
会处理异常。
缺点:需要使用 ExecutorService
,相对较为复杂。
Callable使用案例:
import java.util.concurrent.*;
class MyCallable implements Callable{
public long count ;
MyCallable(long count){
this.count = count;
}
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i <= count; i++) {
sum+=i;
}
return sum;
}
}
public class CallableLearn {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(1);
//创建 Callable 任务
MyCallable task = new MyCallable(100);
//提交 Callable 任务并返回 Future 类型结果
Future<Integer> future = executorService.submit(task);
//获取执行结果
Integer result = future.get();
System.out.println(result);
//关闭线程池
executorService.shutdown();
}
}
补充:Future 类的使用:
Future
类用于表示异步计算的结果,提供了以下方法:
-
get()
:获取结果,如果任务未完成会阻塞。 -
get(long timeout, TimeUnit unit)
:在指定时间内获取结果,超时抛出TimeoutException
。 -
isDone()
:判断任务是否完成。 -
cancel(boolean mayInterruptIfRunning)
:取消任务。
4、Callable接口和FutureTask
FutureTask
是 RunnableFuture
接口的实现类,可以直接作为 Runnable
提交给线程执行。
作用:可以将 Callable
任务包装为 Runnable
代码示例:
public class CallableLearn {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//使用匿名内部类的Lambda写法,创建一个Callable任务
Callable<Integer> callableTask = () -> {
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum+=i;
}
return sum;
};
//使用 FutureTask 将 Callable 包装成 Runnable
FutureTask<Integer> runnableTask = new FutureTask<>(callableTask);
Thread tr = new Thread(runnableTask);
tr.start();
//获取执行结果
Integer res = runnableTask.get();
System.out.println(res); //5050
}
}