Java并发编程系列文章
《一》多线程基础——Java线程与进程的基本概念
《二》多线程基础——Java线程入门类和接口
《三》多线程基础——Java线程组和线程优先级
《四》多线程基础——Java线程生命周期及转换
《五》多线程基础——Java线程间的通信(互斥与协作)
《六》实际应用——如何优雅的关闭线程
《七》实际应用——生产者与消费者模型
并发编程(多线程)
一直以来都是程序员头疼的难题。曾经听别人总结过并发编程的第一原则,那就是不要写并发程序,哈哈哈。后来发现,这样能够显著提高程序响应和吞吐量的利器,哪还能忍得住不会用呢?
整理出《Java并发编程系列文章》,共计7篇,与君共勉。
《六》实际应用——如何优雅的关闭线程
1、开关的方式关闭线程
在实际开发中,什么时候会需要主动关闭线程呢?举个例子,当你用多线程读取Excel中的数据存入数据库,要处理的某个Excel中有100万条数据时,假设你代码中设置10万条数据启动一个线程处理,最多同时启动5个线程。如果启动的线程在处理业务逻辑时报错了,你想立即关闭并重新启一个。废话不多说,直接贴Demo代码:
public class Work extends Thread{
private volatile boolean start = true; //设置开关
@Override
public void run() {
while (start){
System.out.println("业务逻辑正在执行......"); //业务逻辑
}
}
public void shutdown(){
this.start = false;
}
}
public static void main(String[] args) throws InterruptedException {
Work work = new Work();
work.start();
try {
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
work.shutdown(); //主动关闭线程
}
2、打断的方式关闭线程
2.1、线程处于WAITING、TIMED_WAITING
在实际开发中,当你的线程调用了wait()、或者sleep()等方法,进入等待或超时等待,而你又想主动结束这个线程时,就可以适用这种情况。废话不多说,直接贴Demo代码:
public class Work extends Thread{
@Override
public void run() {
while (true){
try {
System.out.println("业务逻辑正在执行......"); //业务逻辑
Thread.sleep(3000);
}catch (InterruptedException e){
System.out.println("正在退出线程执行......");
break; //return
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Work work = new Work();
work.start();
try {
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
work.interrupt();
}
2.2、线程不处于WAITING、TIMED_WAITING
在实际开发中,当你的线程不处于等待或超时等待,而你又想主动结束这个线程时,就可以适用这种情况。废话不多说,直接贴Demo代码:
public class Work extends Thread{
@Override
public void run() {
while (true){
if(Thread.interrupted()){
System.out.println("正在退出线程执行......");
break; //return
}
System.out.println("业务逻辑正在执行......"); //业务逻辑
}
}
}
public static void main(String[] args) throws InterruptedException {
Work work = new Work();
work.start();
try {
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
work.interrupt();
}
3、自定义封装Thread,暴力关闭线程
在实际开发中,当你的线程调用第三方接口阻塞、读一个网络资源超时或者处理业务逻辑阻塞了,你即便修改开关的值或者打断它,依然无法使正处于阻塞中的线程感知到时。而你却想给它设置一个超时时间,超过这个时间就自动关闭。废话不多说,直接贴Demo代码:
public class MyThread {
private Thread executeThread;
private boolean finished = false;
public void execute(Runnable task){
executeThread = new Thread(){
@Override
public void run() {
Thread runner = new Thread(task);
runner.setDaemon(true);
runner.start();
try {
runner.join();
finished = true;
} catch (InterruptedException e) {
//e.printStackTrace();
//关闭线程
}
}
};
executeThread.start();
}
public void shutdown(long mills){
long currentTime = System.currentTimeMillis();
while (!finished){
//任务还在执行中,判断是否超时
if((System.currentTimeMillis() - currentTime) >= mills){
System.out.println("任务超时,需要结束。");
executeThread.interrupt();
break;
}
//任务还在执行中,未超时。让executeThread休眠0.001秒,再判断finished
try {
executeThread.sleep(1);
}catch (InterruptedException e){
System.out.println("执行线程被打断");
break;
}
}
finished = false;
}
}
public static void main(String[] args){
MyThread thread = new MyThread();
long start = System.currentTimeMillis();
thread.execute(()->{
while (true){
}
});
thread.shutdown(10000);
long end = System.currentTimeMillis();
System.out.println(end - start);
}
自定义封装了一个MyThread
类,当我们调用它的execute()
方法时,它会启动一个执行线程,让执行线程将传入的任务线程初始化,并设置成执行线程的守护线程。当启动并join任务线程后,执行线程将阻塞,等任务线程执行完,执行线程才会退出。
我们可以调用它的shutdown(long)
方法,如果任务线程正在执行且已经超时,shutdown()
方法会打断执行线程,因为任务线程是执行线程的守护线程,所以当执行线程被终止,那么任务线程也会终止。