Java多线程(Thread)间通信和共享数据

        多线程间如何通信和共享数据,肯定好多小伙伴都不知道, 或者很久之前知道,现在已经忘却,现在我和大家一起复习一下。

        一、线程间通信

        1、线程间通信:A执行完,B才执行

/**
     * 线程间通信:A执行完,B才执行
     */
    @Test
    public void bWaitA(){
        Thread A = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("A 开始工作!!");
                System.out.println("A 结束工作!!");
            }
        });
        Thread B = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("B 开始等待 A");
                try {
                    A.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("B 开始工作!!");
                System.out.println("B 结束工作!!");
            }
        });
        B.start();
        A.start();
    }

        2、A执行一部分,B执行完,A再执行剩下的部分

    /**
     * A执行一部分,B执行完,A再执行剩下的部分
     * A 1, B 1, B 2, B 3, A 2, A 3
     *
     * 首先创建一个 A 和 B 共享的对象锁 lock = new Object();
     * 当 A 得到锁后,先打印 1,然后调用 lock.wait() 方法,交出锁的控制权,进入 wait 状态;
     * 对 B 而言,由于 A 最开始得到了锁,导致 B 无法执行;直到 A 调用 lock.wait() 释放控制权后, B 才得到了锁;
     * B 在得到锁后打印 1, 2, 3;然后调用 lock.notify() 方法,唤醒正在 wait 的 A;
     * A 被唤醒后,继续打印剩下的 2,3。
     */
    @Test
    public void aWaitB() {
        Object lock = new Object();
        Thread A = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("A 等待锁");
                synchronized (lock) {
                    System.out.println("A 获得锁");
                    System.out.println("A 1");
                    try {
                        System.out.println("A wait 放弃锁控制权,等待再次获取锁控制权");
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("被唤醒,重新获取锁控制权");
                    System.out.println("A 2");
                    System.out.println("A 3");
                }
            }
        });
        Thread B = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("B 等待获取锁控制权");
                synchronized (lock) {
                    System.out.println("B 获取锁控制权");
                    System.out.println("B 1");
                    System.out.println("B 2");
                    System.out.println("B 3");
                    System.out.println("B 执行完毕 调用 notiry 方法");
                    lock.notify();
                }
            }
        });
        A.start();
        B.start();
    }

        3、四个线程 A B C D,其中 D 要等到 A B C 全执行完毕后才执行,而且 A B C 是同步运行的

    /**
     * 四个线程 A B C D,其中 D 要等到 A B C 全执行完毕后才执行,而且 A B C 是同步运行的
     *
     * CountdownLatch 来实现这类通信方式。它的基本用法是:
     * 创建一个计数器,设置初始值,CountdownLatch countDownLatch = new CountDownLatch(2);
     * 在 等待线程 里调用 countDownLatch.await() 方法,进入等待状态,直到计数值变成 0;
     * 在 其他线程 里,调用 countDownLatch.countDown() 方法,该方法会将计数值减小 1;
     * 当 其他线程 的 countDown() 方法把计数值变成 0 时,等待线程 里的 countDownLatch.await() 立即退出,继续执行下面的代码。
     *
     * 执行过程:
     * 其实简单点来说,CountDownLatch 就是一个倒计数器,我们把初始计数值设置为3,
     * 当 D 运行时,先调用 countDownLatch.await() 检查计数器值是否为 0,若不为 0 则保持等待状态;
     * 当A B C 各自运行完后都会利用countDownLatch.countDown(),将倒计数器减 1,
     * 当三个都运行完后,计数器被减至 0;此时立即触发 D 的 await() 运行结束,继续向下执行。
     * 因此,CountDownLatch 适用于一个线程去等待多个线程的情况。
     */
    @Test
    public void dWaitABC() {
        int worker = 3;
        CountDownLatch countDownLatch = new CountDownLatch(worker);
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("D 等待其他线程执行完毕");
                try {
                    countDownLatch.await();
                    System.out.println("所有需要等待的线程都执行完毕,D开始工作");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        for (char threadName='A'; threadName <= 'C'; threadName++) {
            final String threadNameStr = String.valueOf(threadName);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(threadNameStr + " 正在工作");
                    System.out.println(threadNameStr + " 工作完成");
                    countDownLatch.countDown();
                }
            }).start();
        }
    }

        4、个运动员各自准备,等到三个人都准备好后,再一起跑

    /**
     *  三个运动员各自准备,等到三个人都准备好后,再一起跑
     *
     * CyclicBarrier
     * 为了实现线程间互相等待这种需求,我们可以利用 CyclicBarrier 数据结构,它的基本用法是:
     * 先创建一个公共 CyclicBarrier 对象,设置 同时等待 的线程数,CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
     * 这些线程同时开始自己做准备,自身准备完毕后,需要等待别人准备完毕,这时调用 cyclicBarrier.await(); 即可开始等待别人;
     * 当指定的 同时等待 的线程数都调用了 cyclicBarrier.await();时,意味着这些线程都准备完毕好,然后这些线程才 同时继续执行。
     */
    @Test
    public void runABCWhenAllReady() {
        int runner = 3;
        CyclicBarrier cyclicBarrier = new CyclicBarrier(runner);
        final Random random = new Random();
        for (char runnerName='A'; runnerName <= 'C'; runnerName++) {
            final String runnerNameStr = String.valueOf(runnerName);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    long prepareTime = random.nextInt(1000) + 100;
                    System.out.println(runnerNameStr + " 线程正在做准备 " );
                    try {
                        Thread.sleep(prepareTime);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    try {
                        System.out.println(runnerNameStr + " 线程准备完毕等待其他线程准备好");
                        cyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                    System.out.println("所有线程都准备好了,"+runnerNameStr +" 线程开始工作");
                }
            }).start();
        }
        // 让主线程休眠,让里面的线程执行完毕之前,主线程还存在
        try {
            Thread.sleep(60000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

        二、线程数据共享

    /**
     * 线程间数据共享
     * 不同的线程,都有一个属性 ShareData ,并且线程的工作也封装 ShareData中。
     * 不同线程中的run方法执行的都是 ShareData 中指定的封装的方法
     */
    @Test
    public void shareData(){
        ShareData shareData = new ShareData();
        for(int i=1;i<=2;i++){
            new Thread(new MyIncreRunnable(shareData)).start();
            new Thread(new MyDecreRunanble(shareData)).start();
        }
    }
    /**
     * 线程间数据共享
     * 不同的线程,都有一个属性 ShareData ,并且线程的工作也封装 ShareData中。
     * 不同线程中的run方法执行的都是 ShareData 中指定的封装的方法
     */
    @Test
    public void shareData(){
        ShareData shareData = new ShareData();
        for(int i=1;i<=2;i++){
            new Thread(new MyIncreRunnable(shareData)).start();
            new Thread(new MyDecreRunanble(shareData)).start();
        }
    }


class MyIncreRunnable implements Runnable{
    private ShareData shareData;
    public MyIncreRunnable(ShareData shareData) {
        this.shareData = shareData;
    }
    @Override
    public void run() {
        for (int i = 1;i<=10;i++){
            shareData.increment();
        }
    }
}

class MyDecreRunanble implements Runnable{
    private ShareData shareData;
    public MyDecreRunanble(ShareData shareData) {
        this.shareData = shareData;
    }
    @Override
    public void run() {
        for(int i=1;i<=10;i++){
            shareData.decrement();
        }
    }
}

/**
 * 共享数据,对共享数据的操作也在这个对象中完成
 */
class ShareData{
    private int count = 0;
    public synchronized void increment(){
        count++;
        System.out.println(Thread.currentThread().getName()+" inc "+count);
    }
    public synchronized void decrement(){
        count--;
        System.out.println(Thread.currentThread().getName()+" dec " +count);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值