Java线程的创建方式以及线程池的使用
一、线程的创建方式一
/**
* 1.继承thread类,重写run方法
*/
@Test
void test1(){
new threadDemo().start();
}
class threadDemo extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
}
二、线程的创建方式二
/**
* 2.实现runnable接口,重写run方法
*/
@Test
void test2(){
new Thread(new runnableDemo()).start();
}
class runnableDemo implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
}
三、线程的创建方式三
/**
* 3.实现Callable接口,重写call方法
*/
@Test
void test3(){
FutureTask<Integer> futureTask = new FutureTask<>(new callAbleDemo());
new Thread(futureTask, "threadName").start();
Integer result = null;
try {
// 获取子线程执行的结果,此时主线程会被阻塞,会等到计算结果完成后,容易程序阻塞
// 可以通过使用CompletableFuture,解决FutureTask的缺陷问题
result = futureTask.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println(result); // 输出result为45
}
class callAbleDemo implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < 10; i++) {
sum += i;
}
return sum;
}
}
由于futureTask.get()
时会阻塞主线程,我们可以指定超时时间,表示在规定时间内仍未完成则直接抛异常,改造后的代码如下:
/**
* 3.实现Callable接口,重写call方法
*/
@Test
void test3(){
FutureTask<Integer> futureTask = new FutureTask<>(new callAbleDemo());
new Thread(futureTask, "threadName").start();
Integer result = null;
try {
// 获取子线程执行的结果,此时主线程会被阻塞,会等到计算结果完成后,容易程序阻塞
// 可以通过使用CompletableFuture,解决FutureTask的缺陷问题
// result = futureTask.get();
result = futureTask.get(3, TimeUnit.SECONDS); // 指定超时时间,如果未执行完直接抛异常
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
System.out.println(result);
}
class callAbleDemo implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < 10; i++) {
sum += i;
}
try {
TimeUnit.SECONDS.sleep(5); // 沉睡5s,模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
return sum;
}
}
同时我们也可以使用FutureTask
的isDone
方法,这个方法的作用是不断地轮询判断是否操作已经完成,但是这容易耗费cpu资源,改造后的代码如下:
/**
* 3.实现Callable接口,重写call方法
*/
@Test
void test3() throws ExecutionException, InterruptedException {
FutureTask<Integer> futureTask = new FutureTask<>(new callAbleDemo());
new Thread(futureTask, "threadName").start();
Integer result = null;
// isDone轮询,是否已经计算完成,容易耗费cpu资源
while (true){
if (futureTask.isDone()){
// 可以通过使用CompletableFuture,解决FutureTask的缺陷问题
result = futureTask.get();
break;
}else {
System.out.println("还没完成呢");
}
}
System.out.println(result);
}
class callAbleDemo implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < 10; i++) {
sum += i;
}
try {
TimeUnit.SECONDS.sleep(1); // 沉睡1s,模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
return sum;
}
}
我们可以通过使用CompletableFuture
,解决FutureTask
的缺陷问题,FutureTask
类图关系如下:
CompletableFuture
哔哩哔哩链接:https://www.bilibili.com/video/BV1ar4y1x727?p=22&vd_source=7c5f1f4c039688f19024d50ef51aaed1
从java8开始引入CompletableFuture
,是Future
的功能增强版,减少阻塞和轮询,可以传入回调对象,当异步任务完成或者发生异常时,自动调用回调对象的回调方法。
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "----come in");
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("-----1秒钟后出结果:" + result);
return result;
}).whenComplete((v, e) -> {
if (e == null) {
System.out.println("-----计算完成,更新系统UpdateValue:" + v);
}
}).exceptionally(e -> {
e.printStackTrace();<