Java多线程设计模式之顺序控制-两个小案例
案例一
两个线程,保证B线程执行完毕后再让A线程执行
思路一:使用wait/notify,需要synchronized关键字支持
思路二:使用LockSuport的park/unpark,推荐使用
参考代码:
package com.Thread;
import sun.security.ssl.SSLContextImpl;
import java.util.concurrent.locks.LockSupport;
public class SynControl {
//锁对象
public static Object obj = new Object();
//表示t2是否被运行过,为true才允许t1执行
public static boolean t2round = false ;
public static void main(String[] args) {
//waitandnotify();
//parkandunpark();
}
public static void waitandnotify() {
new Thread(()->{
synchronized (obj){
while (!t2round){
//如果t2round还未批准t1,则等待
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t1执行over");
}
},"t1").start();
new Thread(()->{
synchronized (obj){
t2round = true ;
obj.notifyAll(); //唤醒t1
}
System.out.println("t2执行over");
},"t2").start();
}
public static void parkandunpark(){
//注意:private LockSupport() {} // Cannot be instantiated.
// LockSupport lock = new LockSupport() ;
Thread t1 = new Thread(()->{
//当没有『许可』时,当前线程暂停运行;有『许可』时,用掉这个『许可』,当前线程恢复运行
LockSupport.park();
System.out.println("t1执行-over");
});
Thread t2 =new Thread(()->{
t2round = true ;
// 给线程 t1 发放『许可』(多次连续调用 unpark 只会发放一个『许可』)
LockSupport.unpark(t1);
System.out.println("t2执行-over");
},"t2");
t2.start();
t1.start();
}
}
两种方式对比:
可以看到,waitandnotify()
实现上很麻烦:
首先,需要保证先 wait 再 notify,否则 wait 线程永远得不到唤醒。因此使用了『运行标记』来判断该不该wait
第二,如果有些干扰线程错误地 notify 了 wait 线程,条件不满足时还要重新等待,使用了 while 循环来解决此问题
最后,唤醒对象上的 wait 线程需要使用 notifyAll,因为『同步对象』上的等待线程可能不止一个
可以使用 LockSupport 类的 park 和 unpark 来简化上面的题目:
park 和 unpark 方法比较灵活,他俩谁先调用,谁后调用无所谓。并且是以线程为单位进行『暂停』和『恢复』,
不需要『同步对象』和『运行标记』
案例二
线程 1 输出 a 5 次,线程 2 输出 b 5 次,线程 3 输出 c 5 次。现在要求输出 abcabcabcabcabc 怎么实现
思路:使用wait/notify
package com.Thread;
public class SynWaitNotify {
/*线程 1 输出 a 5 次,线程 2 输出 b 5 次,线程 3 输出 c 5 次。现在要求输出 abcabcabcabcabc 怎么实现*/
//决定下一个执行的线程
private int flag ;
private int loopNumber ;
public SynWaitNotify(int flag, int loopNumber) {
this.flag = flag;
this.loopNumber = loopNumber;
}
public void print(int waitFlag, int nextFlag, String str) throws InterruptedException {
for (int i = 0; i < loopNumber ; i++) {
synchronized (this){
while (this.flag!=waitFlag){
this.wait();
}
System.out.println(str);
flag = nextFlag ;
this.notifyAll();
}
}
}
public static void main(String[] args) {
SynWaitNotify syn = new SynWaitNotify(1,5) ;
new Thread(()->{
try {
syn.print(1,2,"a");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(()->{
try {
syn.print(2,3,"b");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(()->{
try {
syn.print(3,1,"c");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}