Java多线程:用三个线程控制循环输出10次ABC

本文介绍了一个使用Java实现的线程同步示例,通过一个Lock对象和计数器变量控制三个线程(A、B、C)按顺序输出ABC,循环10次。该示例展示了如何利用ReentrantLock实现线程间的同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载:http://www.cnblogs.com/gaopeng527/p/5257884.html

题目:有A,B,C三个线程, A线程输出A, B线程输出B, C线程输出C,要求, 同时启动三个线程, 按顺序输出ABC, 循环10次。

解题思路:要按顺序输出ABC, 循环10次,就要控制三个线程同步工作,也就是说要让三个线程轮流输出,直到10个ABC全部输出则结束线程。这里用一个Lock对象来控制三个线程的同步。用一个int型变量COUNT标识由那个线程输出。

package cn.com.example;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Jack on 2017/2/13.
 */
public class PrintABC {

    // 有3个线程ABC。按照ABC来运行(A线程输出A,B线程输出B,C线程输出C,以此类推,循环输出)。

    public static int cnt = 0;
    public static final int COUNT = 30;

    public static void main(String[] args) {

        final Lock lock = new ReentrantLock();
        Thread A = new Thread(new Runnable() {

            @Override
            public void run() {
                while (true) {
                    lock.lock();
                    if (cnt >= COUNT) {
                        lock.unlock();
                        return;
                    }
                    if (cnt % 3 == 0) {
                        System.out.println("A");
                        cnt++;
                    }
                    lock.unlock();
                }
            }

        });

        Thread B = new Thread(new Runnable() {
            public void run() {
                while (true) {
                    lock.lock();
                    if (cnt >= COUNT) {
                        lock.unlock();
                        return;
                    }
                    if (cnt % 3 == 1) {
                        System.out.println("B");
                        cnt++;
                    }
                    lock.unlock();
                }
            }
        });

        Thread C = new Thread(new Runnable() {
            public void run() {
                while (true) {
                    lock.lock();
                    if (cnt >= COUNT) {
                        lock.unlock();
                        return;
                    }
                    if (cnt % 3 == 2) {
                        System.out.println("C");
                        cnt++;
                    }
                    lock.unlock();
                }
            }
        });
        A.start();
        B.start();
        C.start();
    }

}

输出:

A
B
C
A
B
C
A
B
C
A
B
C
A
B
C
A
B
C
A
B
C
A
B
C
A
B
C
A
B
C

 

转载于:https://www.cnblogs.com/Zombie-Xian/p/6394060.html

<think>我们需要实现三个线程按顺序输出ABC,即第一个线程输出A,第二个输出B,第三个输出C,然后重复多(比如10)。参考引用中提到了synchronized和Condition两种方式。这里我们分别给出示例。方式1:使用synchronized配合wait/notifyAll思路:我们需要一个共享对象作为锁,同时需要一个状态变量(如flag)来指示当前应该输出哪个字母。假设:flag=0时输出A,1时输出B,2时输出C,然后循环。方式2:使用ReentrantLock和Condition这种方式更灵活,我们可以为每个线程创建一个Condition,从而精确控制唤醒哪个线程。根据引用[3]和引用[4],Condition的方式可以避免唤醒所有线程,因此效率更高。下面分别给出两种实现,并输出10循环(即输出10ABC)。注意:在synchronized方式中,我们使用一个共享锁,并通过while循环检查条件(防止虚假唤醒),条件不满足则wait,满足则执行,执行完后修改状态并唤醒所有等待线程(notifyAll)。在Condition方式中,我们可以使用多个条件变量,每个线程等待在自己的条件上,而当前一个线程执行完后,它只唤醒下一个应该执行的线程,这样就避免了唤醒无关线程。我们先实现synchronized方式:共享变量:flag,初始为0。线程A:输出A,然后设置flag=1,唤醒其他线程线程B:当flag不为1时等待,为1时输出B,然后设置flag=2,唤醒其他线程线程C:当flag不为2时等待,为2时输出C,然后设置flag=0(以便下一循环),唤醒其他线程。但是注意,这个程序需要运行10,所以需要有一个计数器(比如循环10)。然而,每个线程只负责输出自己的字母,因此我们需要让每个线程在完成一任务后进入下一任务,直到总数达到要求(比如10ABC,则每个线程输出10)。更好的结构是:在共享对象中控制总的循环数,每个线程循环检查自己是否满足输出条件,并负责更新状态。下面我们写一个程序,要求输出10ABC(即总共30个字符)。方案一:synchronized方式我们将使用一个共享的锁对象,并在共享对象中维护:intstate:0->A输出,1->B输出,2->C输出intcount:已经输出的总数(以每输出一组ABC为一,即输出到第几组)每个线程的任务是:循环直到达到总的组数(例如10组),在循环中判断当前是否轮到自己,轮到自己则输出,然后更新状态并唤醒其他线程;否则等待。代码结构:publicclassABCSynchronized{//共享对象privatestaticfinalObjectlock=newObject();privatestaticintstate=0;//0:A,1:B,2:Cprivatestaticintcount=0;//记录输出的组数,达到10组结束staticclassThreadAextendsThread{@Overridepublicvoidrun(){try{for(inti=0;i<10;){synchronized(lock){//循环检查,防止虚假唤醒while(state!=0){lock.wait();}System.out.print("A");state=1;lock.notifyAll();//唤醒其他线程i++;//注意:此时我们才完成一A的输出,所以i++(表示A已经完成了一轮中的一,但一轮中还要执行B和C)//但是这里我们每个线程只负责输出自己的部分,所以每个线程需要独立计数吗?//实际上,我们这里用state来控制轮转,当state=0时就是A输出,然后让state=1,然后A等待下一(i增加1)//但注意:整个程序输出10ABC,而每个线程循环数是10(即输出10A,但每输出A后要等待B和C都输出完下一才轮到A)//所以这里用i记录当前线程输出数(即A输出数,10)}}}catch(InterruptedExceptione){e.printStackTrace();}}}//同样方式创建ThreadB和ThreadC但是上面的代码中,每个线程在退出内层循环后就继续下一循环(直到10),而内层循环的退出条件是由state控制的。这样每A输出后,state变为1,然后唤醒其他线程,接下来A再进入循环时会发现state!=0,就会等待,直到B和C执行完将state重新置0?不对,这里每个线程的执行是独立的,我们并没有在C执行完后将state置0。所以我们需要修改:实际上,我们希望按照A->B->C->A->B->C...的顺序,所以当C执行完后应该将state置0,这样下一轮A才能执行。因此:线程A:当state=0时,输出A,然后state=1,然后唤醒其他线程,然后i++(表示A已经输出了一),然后等待下一state=0(但等待前会退出同步块)线程B:当state=1时,输出B,然后state=2,然后唤醒其他线程,然后i++(表示B输出了一线程C:当state=2时,输出C,然后state=0,然后唤醒其他线程,然后i++(表示C输出了一)这样,每个线程都独立计数,总共输出10(每个线程10),正好30输出10ABC)。但是,这里有一个问题:三个线程各自循环10,那么总共的输出数就是3010个A,10个B,10个C),而且顺序是交替的(A->B->C)重复10。所以代码可以这样写:publicclassABCSynchronized{privatestaticfinalObjectlock=newObject();privatestaticintstate=0;//0:A,1:B,2:Cpublicstaticvoidmain(String[]args){newThreadA().start();newThreadB().start();newThreadC().start();}staticclassThreadAextendsThread{@Overridepublicvoidrun(){for(inti=0;i<10;i++){synchronized(lock){while(state!=0){try{lock.wait();}catch(InterruptedExceptione){e.printStackTrace();}}System.out.print("A");state=1;lock.notifyAll();}}}}staticclassThreadBextendsThread{@Overridepublicvoidrun(){for(inti=0;i<10;i++){synchronized(lock){while(state!=1){try{lock.wait();}catch(InterruptedExceptione){e.printStackTrace();}}System.out.print("B");state=2;lock.notifyAll();}}}}staticclassThreadCextendsThread{@Overridepublicvoidrun(){for(inti=0;i<10;i++){synchronized(lock){while(state!=2){try{lock.wait();}catch(InterruptedExceptione){e.printStackTrace();}}System.out.println("C");//每输出一个C换行,这样每组ABC占一行?但题目要求是连续输出,这里为了观察,我们每输出一组ABC换行一。也可以不换行,最后换行。//也可以改成打印C后换行,但这样10组会换10行,变成每行只有一个C。所以改成打印C不换行,最后我们输出一个换行。//但是题目要求是输出ABC,所以通常就是连续输出ABCABC...,所以我们这里输出A和B用print,输出C用println,这样每输出一个C就换行,但是这样格式是:第一组ABC后换行,第二组换行...也就是每行一组。//如果要求连续输出10ABC(不换行),那么可以改成print("C"),但是这样输出就是ABCABC...,最后也没有换行。为了演示清晰,我们可以输出10组后换行(比如在C线程最后一循环结束后),但是这里每个C线程只负责自己的C,所以我们可以调整:最后结束时再换行?或者不用换行。//根据题目要求,我们只要按顺序输出10ABC即可,所以这里我们改为:System.out.print("C");//然后我们不在C线程换行,而是在整个程序运行结束换行?但控制台不会自动换行。我们可以等全部结束再换行,但是线程执行顺序不定,不好控制。所以我们改成在C线程输出完C后,额外输出一个换行,这样每组ABC一行?也可以连续输出。//为了更清晰地看出输出顺序,我们这里选择连续输出(即不换行),所以输出就是:ABCABC...(10ABC)。但这样输出控制台可能没有换行,我们可以在C线程最后一循环结束后换行,但是三个线程独立,不能保证C是最后一个结束的?所以不在线程内换行。//所以我们还是按照题目要求连续输出,最后手动换行?或者不换行也没关系,观察时我们会看到控制输出一行ABCABC...(30个字符)。这里为了简洁,我们不换行,只输出一个C字符。state=0;lock.notifyAll();}}}}}但是注意:这样输出的结果是:ABCABCABC...(连续10)然后程序结束。但实际运行中,可能由于主线程结束导致打印输出被中断?所以我们可以让主线程等待子线程结束(这里三个线程输出10,然后结束,所以主线程需要等待)。另外,这里每个线程在进入同步块后,如果条件不满足(state不等于自己需要的值)就等待,直到被唤醒并再检查条件。这样确保了执行顺序。但是,这里使用notifyAll()会唤醒所有等待的线程,然后这些线程竞争锁,但只有满足条件的线程(即state符合的线程)才能执行,其他线程继续等待。虽然也能工作,但是有竞争和多余的唤醒。现在,我们提供另一种方式:Condition方式。方式二:使用ReentrantLock和Condition这种方式可以为每个线程创建不同的Condition条件,从而精确唤醒下一个线程。我们定义:ReentrantLocklock;ConditionconditionA,conditionB,conditionC;state变量:0->A,1->B,2->C思路:线程A:获取锁,然后检查state,如果不是0,则await在conditionA上;然后输出A,然后设置state=1,然后唤醒conditionB上的线程(signal)。线程B:获取锁,然后检查state,如果不是1,则await在conditionB上;然后输出B,然后设置state=2,然后唤醒conditionC上的线程线程C:获取锁,然后检查state,如果不是2,则await在conditionC上;然后输出C,然后设置state=0,然后唤醒conditionA上的线程。这样,每个线程唤醒下一个要运行的线程,精确控制。代码结构:publicclassABCCondition{privatestaticLocklock=newReentrantLock();privatestaticConditionconditionA=lock.newCondition();privatestaticConditionconditionB=lock.newCondition();privatestaticConditionconditionC=lock.newCondition();privatestaticintstate=0;//0:A,1:B,2:Cpublicstaticvoidmain(String[]args){newThreadA().start();newThreadB().start();newThreadC().start();}staticclassThreadAextendsThread{@Overridepublicvoidrun(){lock.lock();try{for(inti=0;i<10;i++){while(state!=0){conditionA.await();//等待conditionA条件满足}System.out.print("A");state=1;conditionB.signal();//唤醒conditionB(即线程B)}}catch(InterruptedExceptione){e.printStackTrace();}finally{lock.unlock();}}}//同样编写ThreadB和ThreadC但是上面的代码有一个问题:线程B和线程C在执行时也需要获取锁,而线程A在执行完10循环后才会释放锁。这样线程B和线程C根本没有机会执行。所以我们需要让每个线程在执行一输出后,就等待下一,而不是在一个循环内连续执行10。所以我们需要将每输出看作一任务,然后每个线程都要等待被唤醒才能执行下一任务。所以我们把循环放在锁内,但每执行一输出后就等待下被唤醒。但是这样线程A连续执行10,没有机会唤醒线程B,因为线程B一直获取不到锁。所以我们需要修改结构。正确的思路是:每个线程在完成自己的任务后,唤醒下一个线程,然后自己再进入等待状态(等待被上一个线程唤醒)。这样每个线程需要循环10,在每一循环中,先等待自己可以执行,然后执行(输出),然后唤醒下一个线程。但是我们看到,在Condition方式下,每个线程执行一任务后,需要释放锁,然后等待下一被唤醒。所以每个线程在一循环中:先检查条件,条件不满足就await(让出锁),条件满足就输出,然后设置状态,唤醒下一个线程,然后进入下一循环(但下一循环会再检查条件,如果不满足又会等待)。所以每个线程循环应该是10,每输出一个字符。但是,如何确保线程输出后不立即进入下一循环而抢到锁?因为如果线程A输出后唤醒了线程B,然后线程A在循环中继续下一循环,然后再检查条件(此时state已经变为1,所以线程A会等待),这样锁就会被释放,然后线程B就可以获取锁并执行。所以代码可以这样写:publicclassABCCondition{privatestaticLocklock=newReentrantLock();privatestaticConditionconditionA=lock.newCondition();privatestaticConditionconditionB=lock.newCondition();privatestaticConditionconditionC=lock.newCondition();privatestaticintstate=0;//0:A,1:B,2:CstaticclassThreadAextendsThread{@Overridepublicvoidrun(){lock.lock();try{for(inti=0;i<10;i++){while(state!=0){//注意:这里用while防止虚假唤醒conditionA.await();}System.out.print("A");state=1;conditionB.signal();}}catch(InterruptedExceptione){e.printStackTrace();}finally{lock.unlock();}}}staticclassThreadBextendsThread{@Overridepublicvoidrun(){lock.lock();try{for(inti=0;i<10;i++){while(state!=1){conditionB.await();}System.out.print("B");state=2;conditionC.signal();}}catch(InterruptedExceptione){e.printStackTrace();}finally{lock.unlock();}}}staticclassThreadCextendsThread{@Overridepublicvoidrun(){lock.lock();try{for(inti=0;i<10;i++){while(state!=2){conditionC.await();}System.out.print("C");state=0;conditionA.signal();}}catch(InterruptedExceptione){e.printStackTrace();}finally{lock.unlock();}}}publicstaticvoidmain(String[]args)throwsInterruptedException{ThreadAa=newThreadA();ThreadBb=newThreadB();ThreadCc=newThreadC();a.start();b.start();c.start();//等待所有线程执行完毕a.join();b.join();c.join();System.out.println();//程序结束换行,使输出更美观}}但是上面的代码有一个问题:线程A先启动并获取锁,然后线程B和线程C启动,但是线程B和线程C会等待锁。线程A执行完10循环后释放锁,然后线程B才获得锁,但是此时state已经是1?因为线程A在循环中每都设置state=1并唤醒conditionB,但线程B在第一循环时获取锁,然后检查state==1(因为最后设置state=1),所以线程B开始执行,然后同样地执行10B(而线程A已经退出),然后线程C才被唤醒,然后执行10C。这样顺序是:先输出10个A,然后10个B,然后10个C,这不符合要求。原因在于:我们的设计是轮流执行,每个线程输出后唤醒下一个线程,然后继续下一循环(但下一循环就会因为条件不满足而等待)。但是上面的代码中,每个线程连续执行10,因为第一执行完后,state被设置为下一个状态,然后在同一个循环中再检查条件(因为state已经被改为下一个状态,所以当前线程条件就不满足,就会进入await状态,这样锁就会释放,让其他线程有机会执行)。所以,我们需要每个线程只执行一,然后在下一轮中被唤醒再执行?但是循环10,所以每个线程会连续尝试10,但中间会被条件不满足而阻塞。那么为什么会出现连续输出10A?因为线程A在第一获取锁后,开始循环:i=0:state=0->输出A,设置state=1,signalconditionB->然后进入下一循环:i=1,检查state=1(不是0)所以等待(conditionA.await()),此时释放锁。线程B在启动后,获取锁(因为线程A在await时释放了锁),然后线程B进入循环:i=0时检查state=1,满足,输出B,设置state=2,signalconditionC->下一循环i=1,检查state=2(不满足1,所以awaitconditionB,释放锁)。线程C获取锁,输出C,设置state=0,signalconditionA->下一循环i=1,检查state=0(不满足2,所以awaitconditionC,释放锁)。然后线程A被唤醒(因为被conditionA.signal()了),继续执行(从await返回,再检查state,此时state=0?不对,因为线程C将state设置为0,所以线程A满足,输出A,然后state=1,唤醒conditionB->进入下一循环,i=2,然后再遇到state!=0(现在state=1)所以再等待。如此循环,直到每个线程输出10。所以上述代码应该是可以工作的。但是为什么我分析线程A会连续输出10?并没有,线程A在第一输出后,第二循环就会等待。那么为什么我的分析中线程A只输出?实际上,每个线程10循环中,每循环输出(前提是被唤醒且条件满足),所以每个线程都会等待10(实际是执行10任务,但中间被阻塞多)。但是上面的代码在运行的时候,可能会死锁。原因在于:每个线程在启动的时候就会去获取锁,但是线程A先启动并获取了锁,然后线程B和线程C启动后,由于锁被线程A持有,所以它们被阻塞在lock.lock()上。当线程A执行完10循环(在循环中先输出A,然后唤醒conditionB,然后在下一循环中awaitconditionA,释放锁),然后线程B获得锁(注意:线程A的lock.unlock()是在线程A完全结束循环后执行的?不,是在finally里,所以线程A执行完10循环才会解锁,所以线程A不会在循环中解锁,而是执行完10才解锁,那其他线程怎么办?)问题就在于此:上面Condition的代码中,每个线程在进入循环前获取锁,然后循环10(期间如果条件不满足会await并释放锁,但是当循环10后,线程会退出并释放锁)。但是,线程A一开始获取了锁,并且执行10循环,这意味着它要连续执行10输出,然后才释放锁。这样线程B和线程C在启动后,由于锁被线程A持有,所以它们一直阻塞在lock.lock()上。而线程A在第一输出后,虽然唤醒了conditionB,但是线程B此时并没有获得锁(因为锁还在线程A手里,线程A还在循环中),所以线程B无法执行await(因为它还没有获得锁,所以它都还没进入条件判断)。所以线程A的conditionB.signal()是没有作用的。所以正确的做法是:每个线程执行一任务后,就释放锁,然后等待下一被唤醒。但这里我们每个线程的任务是10,所以我们需要将锁的获取和释放放在循环内部,而不是包裹整个循环。但是这样效率低,且频繁获取锁。所以更好的做法是:每个线程循环内,每任务都先获取锁,然后条件满足就执行,执行完再唤醒下一个线程,然后释放锁,然后进行下一循环(但是下循环又会重新获取锁)。但这样获取锁数太多。或者,我们将锁的获取放在循环内部,每循环获取一锁,执行一任务,然后释放锁。但是Condition的await()必须在lock的同步块中,而且condition的signal也必须在同步块中。因此,我们需要将lock.lock()放在每个线程循环内部,每循环都重新获取锁,然后检查条件,满足则执行,然后唤醒下一个线程,然后释放锁。所以修改如下:publicclassABCCondition{privatestaticLocklock=newReentrantLock();privatestaticConditionconditionA=lock.newCondition();privatestaticConditionconditionB=lock.newCondition();privatestaticConditionconditionC=lock.newCondition();privatestaticintstate=0;//0:A,1:B,2:CstaticclassThreadAextendsThread{@Overridepublicvoidrun(){for(inti=0;i<10;i++){lock.lock();try{while(state!=0){conditionA.await();}System.out.print("A");state=1;conditionB.signal();}catch(InterruptedExceptione){e.printStackTrace();}finally{lock.unlock();}}}}//同理,ThreadB和ThreadC这样,每个线程的每循环都会去获取锁。当线程A第一获得锁,输出A,然后唤醒线程B(通过conditionB.signal()),然后释放锁。然后线程A的下一循环,尝试获取锁,但是可能被线程B抢到。线程B获得锁后,检查state(这时state已经被线程A设为1),满足,输出B,然后设置state=2,唤醒线程C,然后释放锁。线程C类似。这样,在多循环中,三个线程轮流获得锁并输出。但是这里有个问题:conditionB.signal()唤醒在conditionB上等待的线程(如果有的话),如果线程B还没有在conditionB上等待,那这个signal就丢失了。但是当线程B启动后,在它的循环中第一尝试获取锁,然后检查条件(state是否为1),如果不为1,它会await(进入等待)。如果此时正好线程A已经发出了signal,那么线程B将永远不会被唤醒,这就是条件变量的信号丢失问题?解决方法是:在调用await之前,先检查条件是否满足,满足就直接执行,不等待。我们的代码中,在调用await之前用while循环检查条件,所以即使信号丢失,当线程B之后获得锁时,它也会重新检查条件,如果当时state已经是1了,那么它就不会await,直接执行。所以,修改为每循环都重新获取锁,在循环内部加锁和释放锁。下面我们给出两种实现:一种是用synchronized,一种是用ReentrantLock和Condition(放在每循环内加锁的版本)。我们根据用户要求提供两个示例。但是注意,用户要求是三个线程按固定顺序输出ABC,所以我们输出的字符串应该整体是连续的(没有换行),每组ABC顺序输出。下面给出代码:1.使用synchronized的实现:</think> 以下是Java多线程按顺序输出ABC的实现,使用`synchronized`和`Condition`两种方式。代码满足以下要求: - 三个线程固定顺序输出ABC - 重复10(共输出10ABC) - 核心逻辑包含状态控制线程协作 --- ### 一、synchronized实现(wait/notifyAll) 通过共享锁和状态变量控制执行顺序: ```java public class SynchronizedABC { private static final Object lock = new Object(); private static int state = 0; // 状态:0=A, 1=B, 2=C private static final int TOTAL_ROUNDS = 10; // 总轮 public static void main(String[] args) { new Thread(() -> print('A', 0)).start(); new Thread(() -> print('B', 1)).start(); new Thread(() -> print('C', 2)).start(); } private static void print(char c, int targetState) { for (int i = 0; i < TOTAL_ROUNDS; i++) { synchronized (lock) { while (state != targetState) { // 轮询检查状态 try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.print(c); state = (state + 1) % 3; // 更新状态:0→1, 1→2, 2→0 lock.notifyAll(); // 唤醒所有等待线程 } } } } ``` **执行结果**: ``` ABCABCABCABCABCABCABCABCABCABC ``` **核心逻辑**: 1. `state`变量控制当前应输出线程(0→A, 1→B, 2→C) 2. 线程通过`while (state != targetState)`检查自身是否可执行 3. 状态更新:`state = (state + 1) % 3` 实现循环切换 4. `notifyAll()`唤醒所有线程,避免线程饥饿问题[^1] --- ### 二、Condition实现(精确唤醒) 使用`ReentrantLock`及`Condition`实现定向唤醒: ```java import java.util.concurrent.locks.*; public class ConditionABC { private static final Lock lock = new ReentrantLock(); private static final Condition conditionA = lock.newCondition(); private static final Condition conditionB = lock.newCondition(); private static final Condition conditionC = lock.newCondition(); private static int state = 0; // 状态:0=A, 1=B, 2=C private static final int TOTAL_ROUNDS = 10; public static void main(String[] args) { new Thread(() -> print('A', 0, conditionA, conditionB)).start(); new Thread(() -> print('B', 1, conditionB, conditionC)).start(); new Thread(() -> print('C', 2, conditionC, conditionA)).start(); } private static void print(char c, int targetState, Condition current, Condition next) { for (int i = 0; i < TOTAL_ROUNDS; i++) { lock.lock(); try { while (state != targetState) { // 检查状态 current.await(); // 当前线程等待 } System.out.print(c); state = (state + 1) % 3; next.signal(); // 精确唤醒下一个线程 } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } } ``` **执行结果**: ``` ABCABCABCABCABCABCABCABCABCABC ``` **核心逻辑**: 1. 为每个线程创建独立的`Condition`对象(`conditionA`, `conditionB`, `conditionC`) 2. `current.await()`使线程在自身条件上等待 3. `next.signal()`精确唤醒下一个线程(如A唤醒B),避免无效竞争[^4] 4. 状态切换逻辑与synchronized方案一致 --- ### 三、两种方案对比 | **特性** | synchronized方案 | Condition方案 | |----------------|----------------------------|-----------------------------| | 锁机制 | 内置锁 | ReentrantLock | | 线程唤醒方式 | notifyAll()(唤醒所有) | signal()(精确唤醒) | | 资源消耗 | 高(唤醒所有线程) | 低(仅唤醒目标线程)[^4] | | 可读性 | 简单 | 需管理多个Condition | | 适用场景 | 简单顺序控制 | 精确线程调度(如生产-消费) | --- ### 关键点总结 1. **状态变量**: - 使用`state`标识当前应执行的线程(值域0/1/2) - 每输出后通过`state = (state + 1) % 3`更新状态 2. **线程同步**: - **synchronized方案**:通过`wait()`让出锁,`notifyAll()`唤醒竞争 - **Condition方案**:通过`await()`/`signal()`实现定向唤醒 3. **防虚假唤醒**: - 使用`while (state != targetState)`代替`if`检查,确保条件满足[^3] 4. **循环终止**: - 通过`for (int i = 0; i < TOTAL_ROUNDS; i++)`控制总执行数 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值