首先,一个线程就不应该由其他线程来进行强制的中断或者停止,而是应该由线程自己自行停止.所以Thread类中的停止方法都已经被废弃了 不允许在调用了.
其次,既然在Java中没有办法立即停止一条线程,但是停止线程这个需求也是一个刚需,非常重要(比如取消掉耗时的操作),那Java怎么办呢? Java给大家提供了一种用于停止线程的机制 -中断.
中断只是一种协作机制,Java没有给中断增加任何语法,中断的过程去由线程的设计者自己去实现.
若要中断一个线程,你需要手动的调用该线程的interrupt方法,该方法也仅仅是将线程对象的中断标识设成true;
接着你需要自己写代码不断地检测当前线程的标识位,如果为true,表示有线程要求你停止.完全由你自主决定怎么做(自己也可以对自己进行中断操作)
实例方法,仅仅是设置线程的中断状态为true,不会停止线程
静态方法 Thread.interrupted() 他做了两件事
实例方法 判断当前线程是否被中断
static volatile boolean isStop = false;
public static void main(String[] args) {
new Thread(() -> {
while (true) {
if (isStop) {
System.out.println("线程终止");
break;
}
System.out.println("走走走");
}
}, "aa").start();
try {
TimeUnit.SECONDS.sleep(1L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(() -> {
isStop = true;
}, "555").start();
}
static AtomicBoolean atomicBoolean = new AtomicBoolean(false);
public static void main(String[] args) {
new Thread(() -> {
while (true) {
if (atomicBoolean.get()) {
System.out.println("线程终止");
break;
}
System.out.println("走走走");
}
}, "aa").start();
try {
TimeUnit.SECONDS.sleep(1L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(() -> {
atomicBoolean.set(true);
}, "555").start();
}
Thread thread = new Thread(() -> {
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("线程终止");
break;
}
System.out.println("走走走");
}
}, "aa");
thread.start();
try {
TimeUnit.SECONDS.sleep(2L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(() -> {
thread.interrupt();
}, "555").start();
对线程发起中断时,如果此线程在调用Object类的wait() 、 wait(long)或wait(long, int)方法或join() 、 join(long) 、 join(long, int) int) 方法时被阻塞, sleep(long) , or sleep(long, int) , 这个类的方法,那么它的中断状态将被清除,它会收到一个InterruptedException 。
这个异常会导致中断状态被复位为false,导致收到中断信号的线程永远也无法停止 所以必须处理InterruptedException这个异常(通常就是在异常捕获里本线程在调用一下自己的中断方法)
try {
TimeUnit.SECONDS.sleep(1L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
来自于Object基类的本地方法 必须在synchronized修饰的方法或代码块中调用,否则会抛出IllegalMonitorStateException异常,所以他们是强绑定的关系.并且wait和notify方法顺序不能错误 否则会造成阻塞
static Object objectLock = new Object();
new Thread(() -> {
synchronized (objectLock){
try {
objectLock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("被唤醒啦");
}
}, "aaa").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(()->{
synchronized (objectLock){
objectLock.notify();
System.out.println("发出来通知了");
}
}).start();
juc包的类,也需要包裹在Lock类的lock和unlock代码块内,否则会抛出IllegalMonitorStateException异常,await和signal的调用顺序也不能反否则会一直阻塞
static Lock lock = new ReentrantLock();
static Condition condition = lock.newCondition();
new Thread(() -> {
lock.lock();
try {
System.out.println("come in");
condition.await();
System.out.println("被唤醒");
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}, "aaa").start();
new Thread(() -> {
lock.lock();
try {
condition.signal();
System.out.println("发出通知");
} finally {
lock.unlock();
}
}, "bbbb").start();
优势是不需要给代码上锁,park和unpark方法的调用顺序可以是相反的不会阻塞
是因为他底层采用的是通行证的原理 有一个值只能为0或者1的标志位 先执行unpark相当于先发了通行证,后再去执行park的时候也不会阻塞,直接放行 通行证的值上限就是1 多次重复的unpark也不会增加上限
Thread t1 = new Thread(() -> {
System.out.println("come in");
LockSupport.park();
System.out.println("被唤醒");
}, "aaa");
t1.start();
new Thread(() -> {
System.out.println("发出通知");
LockSupport.unpark(t1);
}, "ffffsf").start();