之前介绍了多线程的挂起suspend()和继续执行resume()
也说了他的弊端,不建议使用是一回事,但是并不影响我们去了解他们
下面我们说一下 如何规避其弊端,更好的使用他
这里也就结合了多线程的等待wait() 和唤醒notify()
package com.zmkj.admin.test;
/**
*
* SuspendAndResume 挂起 和 继续执行的问题
* 这里说一下 如何 搞一个比较靠谱的Suspend 方法
*
* @author sunminghao
*/
public class GoodSuspend {
public static Object u = new Object();
public static class ChangeObjectThread extends Thread{
//表示当前线程是否被挂起
//关于volatile 关键词的讲解 https://www.cnblogs.com/dolphin0520/p/3920373.html
volatile boolean suspendme = false;
public void suspendMe() {
suspendme = true;
}
public void resumeMe() {
suspendme = false;
synchronized (this){
//唤醒线程继续执行
notify();
}
}
@Override
public void run() {
while (true) {
//线程会先检查自己是否被挂起,是,执行wait 进行等待
synchronized (this){
while (suspendme) {
try {
//使线程等待,等待唤醒操作
wait();
System.out.println("wait ==========================================================");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
synchronized (u){
System.out.println("in ChangeObjectThread");
}
//Thread.yield() 方法,使当前线程由执行状态,变成为就绪状态,让出cpu时间,在下一个线程执行时候,此线程有可能被执行,也有可能没有被执行。
Thread.yield();
}
}
}
public static class ReadObjectThread extends Thread{
@Override
public void run() {
while (true){
synchronized (u) {
System.out.println("in ReadObjectThread。。。。。。。。");
}
Thread.yield();
}
}
}
public static void main(String[] args) throws InterruptedException {
ChangeObjectThread t1 = new ChangeObjectThread();
ReadObjectThread t2 = new ReadObjectThread();
t1.start();
t2.start();
Thread.sleep(1000);
t1.suspendMe();
System.out.println("suspend t1 2 sec");
Thread.sleep(15000);
System.out.println("resume t1");
//上面线程没有挂起,则执行到这里,执行notify方法,并清除挂起标记,从而正常执行。
t1.resumeMe();
}
/**
* 一、volatile 的特性
*
* 1、保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。(实现可见性)
* 2、禁止进行指令重排序。(实现有序性)
* 3、volatile 只能保证对单次读/写的原子性。i++ 这种操作不能保证原子性。
* 关于volatile 原子性可以理解为把对volatile变量的单个读/写,看成是使用同一个锁对这些单个读/写操作做了同步,就跟下面的SoWhat跟SynSoWhat功能类似哦。
*
* 二、Thread.yield() 方法
* 使当前线程由执行状态,变成为就绪状态,让出cpu时间,在下一个线程执行时候,此线程有可能被执行,也有可能没有被执行。
*
*
* 项目测试过程:
* 1、debugger t1.resumeMe();
* 2、控制台在不断的输出
* in ChangeObjectThread
* in ReadObjectThread。。。。。。。。
* 说明两个线程都在执行;
* 当我们执行到 方法 t1.suspendMe() 时,这里将 suspendme = true 这里会触发t1.wait()方法,将线程t1挂起,处于等待的状态;
* 3、这个时候控制台一直在输出
* in ReadObjectThread。。。。。。。。
* 说明t1 的线程不再被执行,t2 线程可以放肆的输出
*
* 4、当执行到 t1.resumeMe() 方法时,
* (我们有断点,这里我们采用一步一步的执行 效果成明显,要不然控制台很快就被刷满了 会看不到重要的一部分日志)
* (这里我们也可以在 wait() 方法之后的日志输出这一行再打上断点 会看的更直观)
* notif()唤醒了之前被wait的线程,这时候,控制台 就又变成了 ChangeObjectThread 和 ReadObjectThread 交互输出了
*
* 同时也发现 "wait ================================" 这个日志输出,是在 执行了 notify 方法之后才被输出,
* 这样就说明了:线程在 被方法wait 暂停之后,就不再继续执行,而是在被 notify 方法唤醒之后,再继续向下执行
*
*
*
*
*/
}