多线程间通讯问题的几种实现方式

概括

多线程通信问题是一个老生常谈的知识点,今天有空通过一个编程题把所有的实现方式整理一遍。
实现方式有:
1、通过全局变量实现(有多种实现方式)
2、通过wait,notify,notifyAll实现
3、通过lock,condition实现
4、通过LockSupport实现

题目

已知两个字符串"123456789"和"ABCDEFGGH",请用两个线程交替打出字符串每个字符,要求数字首先出现。
这是一道典型的多线程通信的编程题,下面给出多种方式的实现。

实现

1、通过全局变量实现(有多种实现方式)###

/***
 * 使用枚举全局变量实现,实现方式类似与自旋锁原理
 * 不满足条件的时候就一直空转。
 * 通过r公共变量控制两个线程交替执行
 */
public class T01_CAS {
    // 定义两个枚举
    enum ReadyToRun{T1,T2};
    // 定义r变量,控制线程执行
    static volatile ReadyToRun r = ReadyToRun.T1;

    public static void main(String[] args) {
        char[] aI = "123456789".toCharArray();
        char[] aC = "ABCDEFGGH".toCharArray();
        new Thread(() ->{
            for (char c : aI) {
                // r变量不是T1就空转,直到T1才执行
                while (r != ReadyToRun.T1){}
                System.out.print(c);
                r = ReadyToRun.T2;
            }
        },"t1").start();

        new Thread(()->{
            for (char c : aC) {
                while (r != ReadyToRun.T2){}
                    System.out.print(c);
                r = ReadyToRun.T1;
            }
        },"t2").start();
    }
}

执行结果:

1A2B3C4D5E6F7G8G9H
Process finished with exit code 0

也可以通过AtomicInteger等原子类来实现:

public class T01_AtomicInteger {
    // 控制两个线程执行顺序
    static AtomicInteger threadNo = new AtomicInteger(1);

    public static void main(String[] args) {
        char[] aI = "123456789".toCharArray();
        char[] aC = "ABCDEFGGH".toCharArray();
        new Thread(() ->{
            for (char c : aI) {
                while (threadNo.get() != 1){}
                System.out.print(c);
                threadNo.set(2);
            }
        },"t1").start();

        new Thread(()->{
            for (char c : aC) {
                while (threadNo.get() != 2){}
                    System.out.print(c);
                threadNo.set(1);
            }
        },"t2").start();
    }
}

执行结果:

1A2B3C4D5E6F7G8G9H
Process finished with exit code 0

2、通过wait,notify,notifyAll实现

public class T01_Sync_wait_notify {
    // 全局变量,控制让T1先执行,先出数字
    static boolean t1IsStart = false;
    public static void main(String[] args) {
        final Object lockObject = new Object(); // 锁对象
        char[] aI = "123456789".toCharArray();
        char[] aC = "ABCDEFGGH".toCharArray();

        new Thread(() ->{
            synchronized (lockObject) {
                for (char c : aI) {
                    if(!t1IsStart){ //T1执行时发现标记为未启动,修改标记位
                        t1IsStart = true;
                    }
                    System.out.print(c);
                    try {
                        lockObject.notify();
                        lockObject.wait(); // 让出锁
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
                lockObject.notify();
            }
        },"t1").start();

        new Thread(()->{
            synchronized (lockObject) {
                for (char c : aC) {
                    if(!t1IsStart){// 若T2先抢到锁,发现T1未执行,则主动让出锁让T1先执行
                        try {
                            lockObject.wait(); // 让出锁
                        }catch (Exception ex){
                            ex.printStackTrace();
                        }
                    }
                    System.out.print(c);
                    try {
                        lockObject.notify();
                        lockObject.wait(); // 让出锁
                    }catch (Exception ex){
                        ex.printStackTrace();
                    }
                }
                lockObject.notify();
            }
        },"t2").start();        
    }
}

执行结果:

1A2B3C4D5E6F7G8G9H
Process finished with exit code 0

3、通过lock,condition实现

public class T01_Lock_Condition {

    public static void main(String[] args) {
        char[] aI = "123456789".toCharArray();
        char[] aC = "ABCDEFGGH".toCharArray();

        Lock lock = new ReentrantLock();
        Condition condition1 = lock.newCondition(); // 控制线程1
        Condition condition2 = lock.newCondition(); // 控制线程2

        new Thread(() ->{
            try{
                lock.lock();
                for (char c : aI) {
                    System.out.print(c);
                    condition2.signal();// 唤醒线程2
                    condition1.await();// 线程1等待
                }
                condition2.signal();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        },"t1").start();

        new Thread(()->{
            try{
                lock.lock();
                for (char c : aC) {
                    System.out.print(c);
                    condition1.signal();
                    condition2.await();
                }
                condition1.signal();
            }catch (Exception ex){
                ex.printStackTrace();
            }finally {
                lock.unlock();
            }
        },"t2").start();
    }
}

执行结果:

1A2B3C4D5E6F7G8G9H
Process finished with exit code 0

4、通过LockSupport实现


public class T01_LockSupport {
    static Thread t1 = null, t2 = null;

    public static void main(String[] args) {
        char[] aI = "123456789".toCharArray();
        char[] aC = "ABCDEFGGH".toCharArray();
        t1 = new Thread(() ->{
            for (char c : aI) {
                System.out.print(c);
                LockSupport.unpark(t2);// 让t2线程获得执行许可
                LockSupport.park();// 当前线程阻塞
            }
        },"t1");

        t2 = new Thread(()->{
            for (char c : aC) {
                LockSupport.park();// 若T2先执行则当前线程阻塞
                System.out.print(c);
                LockSupport.unpark(t1);// 让t1线程获得执行许可
            }
        },"t2");

        t1.start();
        t2.start();
    }
}
执行结果:

```java
1A2B3C4D5E6F7G8G9H
Process finished with exit code 0

总结

下面实现方式:
3、通过lock,condition实现
4、通过LockSupport实现
是比较优雅的实现方式.

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值