Java 中 线程A B C 三个线程如何让其执行顺序为C-B-A

Java 中 线程A B C 三个线程如何让其执行顺序为C-B-A

由于存在CPU调度的不确定性,所以多线程的执行顺序具有不确定性。主线程有可能比其他线程先执行完,其他线程也有可能比主线程执行完,其他线程之间执行顺序也可能不同 ,那么想让线程顺序执行,那就要用特定的方法来搞定!

· [1] 使用线程的join方法

· [2] 使用主线程的join方法

· [3] 使用线程的wait方法

· [4] 使用线程的线程池方法

· [5] 使用线程的Condition(条件变量)方法

· [6] 使用线程的CountDownLatch(倒计数)方法

· [7] 使用线程的CyclicBarrier(回环栅栏)方法

· [8] 使用线程的Semaphore(信号量)方法

就随便拿CountDownLatch 和 CyclicBarrier玩一玩!!!

1 使用线程的CountDownLatch(倒计数)方法

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;

@Slf4j
public class TestCountDownLatch {
    private static CountDownLatch latch = new CountDownLatch(1);
    private static CountDownLatch latch2 = new CountDownLatch(1);
    public static void main(String[] args) {

        Runnable r=()->{
            try {
                //等待B线程计数为0时,才往下执行
                latch2.await();
                log.info("running");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        Thread t1 = new Thread(r, "A");

        Runnable r2=()->{
            try {
                //等待C线程计数为0时,才往下执行
                latch.await();
                log.info("r2 running");
                //B线程开始计数
                latch2.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        Thread t2 = new Thread(r2, "B");

        Runnable r3=()->{
            log.info("r3 running");
            //C线程开始计数
            latch.countDown();
        };
        Thread t3 = new Thread(r3, "C");

        t3.start();
        t1.start();
        t2.start();

    }
}

2 使用线程的CyclicBarrier(回环栅栏)方法

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

@Slf4j
public class TestCyclicBarrier {
    static CyclicBarrier barrier1 = new CyclicBarrier(2);
    static CyclicBarrier barrier2 = new CyclicBarrier(2);
    public static void main(String[] args) {

        Runnable r=()->{
            try {
                //放开栅栏2
                barrier2.await();
                log.info("running");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        };
        Thread t1 = new Thread(r, "A");

        Runnable r2=()->{
            try {
                //放开栅栏1
                barrier1.await();
                log.info("r2 running");
                //放开栅栏2
                barrier2.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        };
        Thread t2 = new Thread(r2, "B");

        Runnable r3=()->{
            try {
                log.info("r3 running");
                //放开栅栏1
                barrier1.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        };
        Thread t3 = new Thread(r3, "C");

        t3.start();
        t1.start();
        t2.start();

    }
}

执行结果:

00:13:14.520 [C] INFO cn.hb.test.TestCyclicBarrier - r3 running
00:13:14.520 [B] INFO cn.hb.test.TestCyclicBarrier - r2 running
00:13:14.520 [A] INFO cn.hb.test.TestCyclicBarrier - running

3. CountDownLatch 和 CyclicBarrier的区别?

1、CountDownLatch简单的说就是一个线程等待,直到他所等待的其他线程都执行完成并且调用countDown()方法发出通知后,当前线程才可以继续执行。

2、cyclicBarrier是所有线程都进行等待,直到所有线程都准备好进入await()方法之后,所有线程同时开始执行!

3、CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。

4,、CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。如果被中断返回true,否则返回false

CountDownLatch的使用场景:

在一些应用场合中,需要等待某个条件达到要求后才能做后面的事情;同时当线程都完成后也会触发事件,以便进行后面的操作。 这个时候就可以使用CountDownLatch。CountDownLatch最重要的方法是countDown()和await(),前者主要是倒数一次,后者是等待倒数到0,如果没有到达0,就只有阻塞等待了。

CyclicBarrier可以用于多线程计算数据,最后合并计算结果的应用场景。比如我们用一个Excel保存了用户所有银行流水,每个Sheet保存一个帐户近一年的每笔银行流水,现在需要统计用户的日均银行流水,先用多线程处理每个sheet里的银行流水,都执行完之后,得到每个sheet的日均银行流水,最后,再用barrierAction用这些线程的计算结果,计算出整个Excel的日均银行流水。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用线程的 wait() 和 notify() 方法来实现按顺序打印ABC的需求。具体实现如下: ```java public class PrintABC { private int times; // 打印次数 private int state; // 当前状态:0-A,1-B,2-C public PrintABC(int times) { this.times = times; this.state = 0; } public synchronized void printA() throws InterruptedException { for (int i = 0; i < times; i++) { while (state != 0) { wait(); } System.out.print("A"); state = 1; notifyAll(); } } public synchronized void printB() throws InterruptedException { for (int i = 0; i < times; i++) { while (state != 1) { wait(); } System.out.print("B"); state = 2; notifyAll(); } } public synchronized void printC() throws InterruptedException { for (int i = 0; i < times; i++) { while (state != 2) { wait(); } System.out.print("C"); state = 0; notifyAll(); } } } ``` 在主函数创建三个线程,分别调用 PrintABC 类的 printA()、printB() 和 printC() 方法: ```java public static void main(String[] args) { PrintABC printABC = new PrintABC(10); Thread threadA = new Thread(() -> { try { printABC.printA(); } catch (InterruptedException e) { e.printStackTrace(); } }); Thread threadB = new Thread(() -> { try { printABC.printB(); } catch (InterruptedException e) { e.printStackTrace(); } }); Thread threadC = new Thread(() -> { try { printABC.printC(); } catch (InterruptedException e) { e.printStackTrace(); } }); threadA.start(); threadB.start(); threadC.start(); } ``` 执行结果: ```java ABCABCABCABCABCABCABCABCABCABC ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值