Java多线程设计模式之顺序控制-两个小案例

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();
    }

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值