中秋节还在家写文章,绝对是真爱...


Java 并发工具包中 java.util.concurrent.ExecutorService 接口定义了线程池任务提交、获取线程池状态、线程池停止的方法等。

 

JDK 1.8 中,线程池的停止一般使用 shutdown()、shutdownNow()、shutdown() + awaitTermination(long timeout, TimeUnit unit) 方法。

 

1、shutdown() 方法源码中解释

     * Initiates an orderly shutdown in which previously submitted
    * tasks are executed, but no new tasks will be accepted.
    * Invocation has no additional effect if already shut down.
  • 有序关闭,已提交任务继续执行

  • 不接受新任务

 

2、shutdownNow() 方法源码中解释

     * Attempts to stop all actively executing tasks, halts the
    * processing of waiting tasks, and returns a list of the tasks
    * that were awaiting execution.
  • 尝试停止所有正在执行的任务

  • 停止等待执行的任务,并返回等待执行的任务列表

 

3、awaitTermination(long timeout, TimeUnit unit) 方法源码中解释

     * Blocks until all tasks have completed execution after a shutdown
    * request, or the timeout occurs, or the current thread is
    * interrupted, whichever happens first.
    *
    * @param timeout the maximum time to wait
    * @param unit the time unit of the timeout argument
    * @return {@code true} if this executor terminated and
    *         {@code false} if the timeout elapsed before termination
    * @throws InterruptedException if interrupted while waiting
  • 收到关闭请求后,所有任务执行完成、超时、线程被打断,阻塞直到三种情况任意一种发生

  • 参数可以设置超时时间与超时单位

  • 线程池关闭返回 true;超过设置时间未关闭,返回 false

 

实践:

1、使用 Executors.newFixedThreadPool(int nThreads) 创建固定大小线程池,测试 shutdown() 方法

package constxiong.concurrency.a013;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* 测试固定数量线程池 shutdown() 方法
* @author ConstXiong
*/

public class TestFixedThreadPoolShutdown {

public static void main(String[] args) {
//创建固定 3 个线程的线程池
ExecutorService threadPool = Executors.newFixedThreadPool(3);

//向线程池提交 10 个任务
for (int i = 1; i <= 10; i++) {
final int index = i;
threadPool.submit(() -> {
System.out.println("正在执行任务 " + index);
//休眠 3 秒
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}

//休眠 4 秒
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}

//关闭线程池
threadPool.shutdown();
}

}

打印结果如下,可以看出,主线程向线程池提交了 10 个任务,休眠 4 秒后关闭线程池,线程池把 10 个任务都执行完成后关闭了。

正在执行任务 1
正在执行任务 3
正在执行任务 2
正在执行任务 4
正在执行任务 6
正在执行任务 5
正在执行任务 8
正在执行任务 9
正在执行任务 7
正在执行任务 10

 

2、使用 Executors.newFixedThreadPool(int nThreads) 创建固定大小线程池,测试 shutdownNow() 方法

package constxiong.concurrency.a013;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* 测试固定数量线程池 shutdownNow() 方法
* @author ConstXiong
*/

public class TestFixedThreadPoolShutdownNow {

public static void main(String[] args) {
//创建固定 3 个线程的线程池
ExecutorService threadPool = Executors.newFixedThreadPool(3);

//向线程池提交 10 个任务
for (int i = 1; i <= 10; i++) {
final int index = i;
threadPool.submit(() -> {
System.out.println("正在执行任务 " + index);
//休眠 3 秒
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}

//休眠 4 秒
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}

//关闭线程池
List<Runnable> tasks = threadPool.shutdownNow();
System.out.println("剩余 " + tasks.size() + " 个任务未执行");
}

}

打印结果如下,可以看出,主线程向线程池提交了 10 个任务,休眠 4 秒后关闭线程池,线程池执行了 6 个任务,抛出异常,打印返回的剩余未执行的任务个数。

正在执行任务 1
正在执行任务 2
正在执行任务 3
正在执行任务 4
正在执行任务 6
正在执行任务 5
剩余 4 个任务未执行
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at constxiong.concurrency.a013.TestFixedThreadPoolShutdownNow.lambda$0(TestFixedThreadPoolShutdownNow.java:24)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at constxiong.concurrency.a013.TestFixedThreadPoolShutdownNow.lambda$0(TestFixedThreadPoolShutdownNow.java:24)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at constxiong.concurrency.a013.TestFixedThreadPoolShutdownNow.lambda$0(TestFixedThreadPoolShutdownNow.java:24)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

 

3、Executors.newFixedThreadPool(int nThreads) 创建固定大小线程池,测试 awaitTermination(long timeout, TimeUnit unit) 方法

package constxiong.concurrency.a013;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
* 测试固定数量线程池 shutdownNow() 方法
* @author ConstXiong
*/

public class TestFixedThreadPoolAwaitTermination {

public static void main(String[] args) {
//创建固定 3 个线程的线程池
ExecutorService threadPool = Executors.newFixedThreadPool(3);

//向线程池提交 10 个任务
for (int i = 1; i <= 10; i++) {
final int index = i;
threadPool.submit(() -> {
System.out.println("正在执行任务 " + index);
//休眠 3 秒
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}

//关闭线程池,设置等待超时时间 3 秒
System.out.println("设置线程池关闭,等待 3 秒...");
threadPool.shutdown();
try {
boolean isTermination = threadPool.awaitTermination(3, TimeUnit.SECONDS);
System.out.println(isTermination ? "线程池已停止" : "线程池未停止");
} catch (InterruptedException e) {
e.printStackTrace();
}

//再等待超时时间 20 秒
System.out.println("再等待 20 秒...");
try {
boolean isTermination = threadPool.awaitTermination(20, TimeUnit.SECONDS);
System.out.println(isTermination ? "线程池已停止" : "线程池未停止");
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}

打印结果如下,可以看出,主线程向线程池提交了 10 个任务,申请关闭线程池 3 秒超时,3 秒后线程池并未成功关闭;再获取线程池关闭状态 20 秒超时,线程池成功关闭。

正在执行任务 1
正在执行任务 3
正在执行任务 2
设置线程池关闭,等待 3 秒...
线程池未停止
正在执行任务 4
正在执行任务 6
再等待 20 秒...
正在执行任务 5
正在执行任务 7
正在执行任务 9
正在执行任务 8
正在执行任务 10
线程池已停止

 

总结:

1、调用 shutdown() 和 shutdownNow() 方法关闭线程池,线程池都无法接收新的任务

2、shutdown() 方法会继续执行正在执行未完成的任务;shutdownNow() 方法会尝试停止所有正在执行的任务

3、shutdown() 方法没有返回值;shutdownNow() 方法返回等待执行的任务列表

4、awaitTermination(long timeout, TimeUnit unit) 方法可以获取线程池是否已经关闭,需要配合 shutdown() 使用

5、shutdownNow() 不一定能够立马结束线程池,该方法会尝试停止所有正在执行的任务,通过调用 Thread.interrupt() 方法来实现的,如果线程中没有 sleep() 、wait()、Condition、定时锁等应用, interrupt() 方法是无法中断当前的线程的。


更多相关文章

  1. Java 中线程池包含哪些状态?
  2. 如何创建、启动 Java 线程?
  3. Executors如何创建线程池?
  4. 什么是线程?什么是进程?为什么要有线程?有什么关系与区别?
  5. 什么是线程池?
  6. 线程包括哪些状态?状态之间是如何转变的?
  7. 什么是守护线程?
  8. 如何优雅地停止一个线程?
  9. 从模版方法模式到 SPI 演变 :好的思想通用而持久

随机推荐

  1. Android 5.0 默认水波纹背景属性,可设置
  2. android在RelativeLayout里的TextView或
  3. 利用oom_adj提高Application所在进程的优
  4. 丰富多彩的Android onTouch事件
  5. linux下部署android模拟器
  6. Android:WebView与Javascript交互(相互调用
  7. Android(安卓)Studio 提示Error running
  8. android之grideView书架问题
  9. Android是什么
  10. Android EditText不显示光标的解决方法