两个线程分别交替打印A、B的一种Java写法

本文介绍了一种使用条件变量和AtomicBoolean实现Java线程间通信的方法,以达到交替打印'A'和'B'的目标。代码示例展示了如何通过这两个工具确保线程安全和可见性。
  • 大致思路是用条件变量作为两个线程通信的工具,然后用一个AtomicBoolean的变量作为flag保证线程间的可见性

  • 代码如下

      import java.util.concurrent.atomic.AtomicBoolean;
      import java.util.concurrent.locks.Condition;
      import java.util.concurrent.locks.Lock;
      import java.util.concurrent.locks.ReentrantLock;
    
      class APrinter implements Runnable {
    
          private final Lock lock;
          private final AtomicBoolean flag;
          private final Condition waitA, waitB;
    
          APrinter(Lock lock, AtomicBoolean flag, Condition waitA, Condition waitB) {
              this.lock = lock;
              this.flag = flag;
              this.waitA = waitA;
              this.waitB = waitB;
          }
    
          @Override
          public void run() {
              while (true) {
                  try {
                      lock.lock();
    
                      while (flag.get()) {
                          try {
                              waitB.await();
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                      }
    
                      System.out.println("A");
                      Thread.sleep(1000);
                      
                      flag.set(true);
                      waitA.signal();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  } finally {
                      lock.unlock();
                  }
              }
          }
      }
    
      class BPrinter implements Runnable {
          private final Lock lock;
          private final AtomicBoolean flag;
          private final Condition waitA, waitB;
    
          BPrinter(Lock lock, AtomicBoolean flag, Condition waitA, Condition waitB) {
              this.lock = lock;
              this.flag = flag;
              this.waitA = waitA;
              this.waitB = waitB;
          }
    
          @Override
          public void run() {
              while (true) {
                  try {
                      lock.lock();
    
                      while (!flag.get()) {
                          try {
                              waitA.await();
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                      }
    
                      System.out.println("B");
                      Thread.sleep(1000);
    
                      flag.set(false);
                      waitB.signal();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  } finally {
                      lock.unlock();
                  }
              }
          }
      }
    
  • 测试类

      class Test {
    
          public static void main(String[] args) throws InterruptedException {
    
              final Lock lock = new ReentrantLock();
              final Condition waitA = lock.newCondition();
              final Condition waitB = lock.newCondition();
              AtomicBoolean flag = new AtomicBoolean(false);
    
              Thread thread1 = new Thread(new APrinter(lock, flag, waitA, waitB));
              Thread thread2 = new Thread(new BPrinter(lock, flag, waitA, waitB));
    
               thread1.start();
               thread2.start();
    
                thread1.join();
                thread2.join();
          }
      }
    
<think>好的,我现在需要帮助用户解决如何用Java创建两个线程,分别通过继承Thread类和实现Runnable接口的方式,输出100个1-26的数字和100个A-Z的字母。首先,我得理解用户的具体需求。用户希望两个线程分别输出数字和字母各100次,但1-26和A-Z每个只有26个元素,所以可能需要循环多次,直到达到100次。不过,用户可能的意思是每个线程输出100个字符,数字线程重复打印1-26直到满100个,字母同理。或者可能是每个线程输出100次完整的1-26和A-Z循环?需要进一步确认,但根据示例代码中的引用,比如引用3中的代码是打印26次,用户的问题可能希望每个线程输出100次,但内容循环1-26和A-Z。但用户的问题描述可能有误,因为输出100个1-26可能指的是每个数字输出100次,或者循环直到总共输出100个数字。需要仔细分析。接下来,用户要求两个线程分别使用继承Thread和实现Runnable的方式。这意味着一个线程类继承Thread,另一个类实现Runnable接口。然后需要协调这两个线程的输出,可能交替打印数字和字母,或者同时运行,但需要同步控制,确保正确输出。查看用户提供的引用,特别是引用1、2、3中的代码,都是使用synchronized块和wait/notify机制来实现线程间的交替执行。例如,引用3中的代码通过共享锁对象,让两个线程交替打印数字和字母,每次打印一个后等待对方线程唤醒。用户的问题可能希望类似的交替输出,但需要两个线程分别用不同的创建方式。但用户的问题中并没有明确说明是否需要交替输出,还是各自独立输出。原问题描述是“输出100个126和100个AZ”,可能是指数字线程输出1-26循环直到100个,字母线程输出A-Z循环直到100个,各自独立运行。但根据引用中的例子,可能用户希望的是交替打印,比如数字和字母交替输出,形成1A2B3C...这样的模式。但用户的问题描述不够明确,需要进一步分析。根据用户提供的引用,特别是引用3中的代码,两个线程交替打印数字和字母,每个线程打印26次,使用wait和notify进行同步。用户的问题可能希望类似的效果,但扩展到100次。但1-26和A-Z每个周期是26个元素,所以输出100个可能需要循环多次,例如数字线程输出1-26四次(104次),然后截断到100次,或者调整循环次数。或者用户可能希望每个线程输出100个元素,每个元素依次循环1-26和A-Z。例如,数字线程输出1,2,...,26,1,2,...,26...直到100次,字母同理。但根据用户的问题描述,“输出100个126和100个AZ”,可能更准确的是每个线程输出100个元素,其中数字线程循环输出1-26,字母线程循环输出A-Z,每个线程独立运行,不需要交替。但用户提供的引用中的例子都是交替打印,所以可能存在混淆。需要结合用户的问题和引用中的示例来推断。 假设用户希望两个线程分别输出数字和字母,各100次,数字从1到26循环,字母从A到Z循环,每个线程独立运行,不需要交替。这种情况下,两个线程可以同时运行,各自打印自己的内容,但需要确保线程安全,避免输出混乱。但如果是交替打印,则需要同步机制,如引用中的例子。但用户的问题可能更倾向于交替打印,类似于引用中的示例,但需要两个线程分别使用不同的创建方式(继承Thread和实现Runnable)。例如,一个线程打印数字,另一个打印字母,交替进行,总共输出100个数字和100个字母。或者每个线程各输出100次自己的序列,但需要同步控制,确保正确交替。需要明确用户的需求。根据用户的问题描述:“输出100个126和100个AZ”,可能是指每个线程输出100次,数字线程输出1-26循环,字母线程输出A-Z循环,各100次。例如,数字线程打印1到26,重复4次(4*26=104次),然后调整到100次;字母同理。或者每个线程打印100个字符,每个字符依次循环1-26或A-Z。但根据用户提供的引用中的代码,例如引用3,两个线程交替打印数字和字母,每次打印一个后切换。所以用户可能希望类似的效果,但扩展到100次。例如,数字线程打印1,字母打印A,数字打印2,字母B,依此类推,直到总共100个数字和100个字母。但这样需要两个线程严格交替,每个打印一次,总共200次输出。但用户的问题中可能希望每个线程各输出100次,所以可能需要调整同步机制。或者,用户可能希望每个线程独立输出,但需要确保线程安全,避免输出交错混乱。例如,数字线程连续输出1-26多次,字母线程连续输出A-Z多次,但输出时可能交错,导致输出混乱。因此可能需要同步控制,让每个线程在输出时独占锁,确保输出完整。但根据用户提供的引用中的代码,都是交替打印,所以更可能用户希望的是交替输出,例如数字和字母交替出现,每个线程各输出100次。但如何协调两个线程各输出100次呢?或者每个线程输出26次,循环多次,直到达到100次?这需要进一步分析。现在,回到用户的问题,需要创建两个线程,一个继承Thread,另一个实现Runnable,分别输出100个数字(1-26循环)和100个字母(A-Z循环)。需要结合两种线程创建方式,并处理同步问题。首先,设计两个线程类: 1. NumberThread继承 Thread类,负责打印数字。2.LetterRunnable实现 Runnable接口,负责打印字母。然后,主线程创建这两个线程并启动。需要确保两个线程能够交替打印,或者各自独立运行,但输出不混乱。如果用户希望交替打印,则需要使用同步机制,如synchronized块,配合wait和notify。例如,每次数字线程打印一个数字后,通知字母线程打印,然后自己等待,反之亦然。这样交替进行,直到各自完成100次输出。 但如何确定循环次数?例如,每个数字和字母各打印100次,可能需要每个线程循环100次,每次打印对应的数字或字母。但如果是1-26循环,那么100次的话,每个数字可能需要循环3次(3*26=78),然后剩下的22次再打印1-22。或者,每次打印时取模26的值。例如,数字线程的run方法中,循环100次,每次打印(i%26)+1,i从0到99。字母线程同理,打印 (i%26)+ 'A'。 但这样输出的数字和字母可能会交错,例如数字线程打印1,字母线程打印A,但可能同时运行导致输出混乱。因此,是否需要同步控制,使得输出是顺序的?例如,数字和字母交替打印,或者各自独立但输出时不被中断。 用户可能希望两个线程同时运行,但输出时不被其他线程打断,所以每个线程打印时需获得锁,确保输出完整。例如,使用一个共享锁对象,每个线程打印前获取锁,打印完成后释放锁。这样,两个线程会竞争锁,导致输出顺序不确定,但每个输出不会被中断。或者,用户希望两个线程交替执行,严格按顺序打印数字和字母。例如,数字打印1,字母打印A,数字打印2,字母B,依此类推。这需要更复杂的同步机制,如使用wait和notify,确保每次只有一个线程执行。但根据用户提供的引用中的代码,例如引用3,两个线程交替打印数字和字母,每个打印一个后等待对方唤醒。因此,用户的问题可能希望类似的效果,但使用两种不同的线程创建方式,并且输出100次。 因此,解决方案需要: 1.创建两个线程,一个继承Thread,另一个实现Runnable。2.使用同步机制(synchronized,wait,notify)来协调两个线程交替打印数字和字母。3.确保每个线程打印100次,循环1-26和A-Z。 但如何将循环次数调整为100次?例如,每个线程需要打印100次,但每次打印的内容是1-26循环。例如,数字线程打印1,2,...,26,1,2,...,26...直到100次。同样字母线程打印A,B,...,Z,A,B,...直到100次。或者,每个线程打印100个字符,每个字符依次循环1-26或A-Z。 但根据用户的问题描述,可能需要每个线程输出100个字符,每个字符按顺序循环1-26或A-Z。例如,数字线程输出1到26四次,得到104个字符,然后调整到100次,可能需要截断。或者,使用模运算,i从0到99,每次输出(i%26)+1。 但如何协调两个线程交替打印?例如,引用3中的代码是每个线程打印26次,交替进行。现在需要扩展到100次,每个线程打印100次,交替执行。但这样的话,每个线程需要循环100次,每次打印一个字符,然后切换。但这样会导致总共200次输出(100数字+100字母),交替执行。但如何实现两个线程打印100次,交替进行?例如,数字线程打印1,字母线程打印A,数字打印2,字母B,依此类推,直到各打印100次。但这样的话,每个字符需要交替打印,但每个线程需要打印100次,所以总共需要200次交替。但这样每个线程的循环次数是100次,每次打印一个字符,然后等待对方线程打印。但根据引用3中的代码,每个线程循环26次,打印一个字符后切换。现在需要修改为循环100次,同时保持交替。因此,解决方案需要: -共享锁对象,用于同步。 -两个线程,一个打印数字,一个打印字母。-每个线程循环100次,每次打印对应的字符,然后等待对方线程唤醒。但这样,每个线程需要打印100次,交替执行。例如,数字线程打印1,然后唤醒字母线程,自己等待。字母线程打印A,唤醒数字线程,自己等待。依此类推,直到各打印100次。但需要确保每个线程打印完100次后退出循环,避免无限等待。因此,代码结构大致如下: 共享锁对象:Object lock= newObject();数字线程(继承Thread类):publicclassNumberThreadextends Thread{private Objectlock;privateint count=0;publicNumberThread(Object lock) {this.lock= lock;}@Overridepublic voidrun(){synchronized (lock){while (count <100) {System.out.print((count%26)+1);count++;lock.notifyAll();try {lock.wait();}catch (InterruptedExceptione){e.printStackTrace();}}lock.notifyAll(); //防止另一个线程最后处于等待状态}} }字母线程(实现Runnable接口):public classLetterRunnable implementsRunnable {privateObject lock;private intcount =0;publicLetterRunnable(Objectlock){this.lock =lock;}@Overridepublicvoid run() {synchronized(lock) {while(count<100){System.out.print((char)('A' +(count %26)));count++;lock.notifyAll();try{lock.wait();} catch(InterruptedException e) {e.printStackTrace();}}lock.notifyAll();//防止另一个线程最后处于等待状态}}} 主方法:public staticvoid main(String[]args){Object lock= newObject();NumberThread numberThread =new NumberThread(lock);ThreadletterThread= newThread(newLetterRunnable(lock));numberThread.start();letterThread.start();} 但这样可能存在一个问题:当其中一个线程完成100次打印后,另一个线程可能还在等待,导致程序无法退出。因此,需要在循环结束后唤醒对方线程,使其可以退出。例如,在数字线程的循环结束后,执行lock.notifyAll(),这样字母线程在最后一次等待后被唤醒,检查count是否达到100,然后退出循环。同样,字母线程在完成100次后,唤醒数字线程,使其退出。 这样,两个线程可以正常结束。但需要考虑线程启动的顺序,如果数字线程先获得锁,开始打印,然后唤醒字母线程交替执行。但可能存在启动顺序的问题,需要确保其中一个线程先执行,否则可能都进入等待状态导致死锁。例如,如果两个线程同时启动,数字线程先获得锁,开始打印,然后唤醒字母线程,自己等待。字母线程获得锁后,开始打印,唤醒数字线程,自己等待,依此类推。但需要确保初始状态下,哪个线程先执行。例如,在引用3的代码中,两个线程启动后,可能由系统调度决定谁先获得锁。但需要确保在初始状态下,其中一个线程可以开始执行,否则可能都进入等待。例如,在数字线程的run方法中,第一次打印后唤醒对方,自己等待。而字母线程的run方法中,第一次会检查count是否小于100,然后打印,唤醒对方,自己等待。但如果字母线程先获得锁,count初始为0,所以会打印A,count变为1,唤醒数字线程,自己等待。数字线程获得锁后,count初始为0,打印1,count变为1,唤醒字母线程,自己等待。依此类推,交替执行。但可能存在的问题是,当两个线程都启动后,其中一个先获得锁,另一个处于阻塞状态。例如,数字线程先获得锁,开始循环,打印数字,然后唤醒字母线程,自己等待。字母线程被唤醒后,获得锁,开始循环,打印字母,唤醒数字线程,自己等待。这样交替进行,直到各自完成100次。但需要测试这种情况是否可行,是否存在死锁风险。例如,当最后一个循环时,数字线程打印第100次后,唤醒字母线程,自己退出循环。字母线程被唤醒后,检查count=100,退出循环,也唤醒数字线程(但此时数字线程已经结束)。这样程序可以正常结束。因此,这样的代码结构应该是可行的。现在,需要将这两个线程分别用继承Thread类和实现Runnable接口的方式实现。例如,数字线程继承Thread,字母线程作为Runnable的实现类。 然后,在主方法中创建并启动这两个线程。 另外,需要处理输出的格式,确保每个数字和字母正确交替,没有重复或遗漏。例如,数字线程打印1,字母线程打印A,数字打印2,字母B,依此类推,直到各打印100次。但这样每个线程需要打印100次,而每个循环中的count变量是各自独立的。例如,数字线程的count从0到99,字母线程的count也是0到99,这样每个打印100次,每次对应count%26的值。但这样输出的内容会是数字1-26循环4次(4*26=104),然后截断到100次,而字母同理。但用户的问题可能希望每个线程输出100个字符,每个字符依次循环1-26或A-Z,所以使用count%26是正确的。现在,编写具体的代码:NumberThread类: publicclass NumberThread extendsThread {privatefinal Objectlock;privateint count=0;publicNumberThread(Object lock) {this.lock= lock;}@Overridepublic voidrun(){synchronized (lock){while (count <100) {System.out.print((count%26)+1);count++;lock.notifyAll();try {if(count<100){lock.wait();}}catch (InterruptedExceptione){e.printStackTrace();}}lock.notifyAll(); //确保另一个线程结束等待}} }LetterRunnable类: publicclass LetterRunnableimplements Runnable{private finalObject lock;private intcount =0;public LetterRunnable(Object lock) {this.lock= lock;}@Overridepublic voidrun(){synchronized (lock){while (count <100) {System.out.print((char) ('A'+ (count %26)));count++;lock.notifyAll();try{if (count <100) {lock.wait();}}catch (InterruptedExceptione){e.printStackTrace();}}lock.notifyAll(); //确保另一个线程结束等待}} }主方法: publicclass Main{public staticvoid main(String[]args){Object lock= newObject();NumberThread numberThread =new NumberThread(lock);ThreadletterThread= newThread(newLetterRunnable(lock));numberThread.start();letterThread.start();}} 这样,两个线程交替打印数字和字母,各100次。例如,数字线程打印1,字母打印A,数字打印2,字母B,依此类推,直到各自打印100次。但需要注意,输出的顺序可能受到线程调度的影啊,例如,如果字母线程先获得锁,可能会先打印A,但根据代码中的同步机制,两个线程交替执行。但这里可能存在一个问题:当两个线程同时启动时,谁先获得锁?例如,数字线程可能先进入同步块,开始打印,然后唤醒字母线程,自己等待。字母线程被唤醒后,进入同步块,打印字母,唤醒数字线程,自己等待,依此类推。这样交替执行是正确的。 但需要测试代码是否正确,是否存在死锁或提前退出的情况。例如,当数字线程打印到第100次后,会退出循环,并执行lock.notifyAll(),然后释放锁。字母线程被唤醒后,检查count=100,退出循环,同样执行lock.notifyAll(),程序结束。这样,代码应该可以正确运行,输出交替的数字和字母,各100次,每个线程使用不同的创建方式。但用户的问题中可能希望输出的是100个数字和100个字母,各自独立,而不是交替。例如,数字线程输出1-26循环4次(共104次),然后停止,但用户要求100次,所以需要调整循环次数。或者,使用模运算,每个线程循环100次,每次打印对应的字符。 但根据用户提供的引用中的代码,交替打印是正确的,所以当前解决方案符合用户的需求。 此外,需要确保输出正确,例如,数字从1开始,每次递增,循环26,而字母从A开始,每次递增,循环26。例如,count=0时,数字是1,字母是A;count=1时,数字是2,字母是B,依此类推。总结,用户的问题需要两个线程,分别以继承Thread和实现Runnable的方式创建,使用同步机制交替打印数字和字母各100次,循环1-26和A-Z。以上代码实现了这一点。</think>以下是根据您需求实现的Java线程方案,包含继承Thread类和实现Runnable接口两种方式,实现交替打印数字和字母的功能: ### 实现步骤 1. **共享锁对象**:用于线程间的同步控制 2. **数字线程类**:继承`Thread`类,循环打印1-26 3. **字母线程类**:实现`Runnable`接口,循环打印A-Z 4. **同步控制**:通过`wait()`和`notifyAll()`实现交替打印 ```java // 数字线程(继承Thread类) class NumberThread extends Thread { private final Object lock; private int count = 0; public NumberThread(Object lock) { this.lock = lock; } @Override public void run() { synchronized (lock) { while (count < 100) { System.out.print((count % 26) + 1); // 循环输出1-26 count++; lock.notifyAll(); try { if (count < 100) lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } lock.notifyAll(); // 确保唤醒最后等待的线程 } } } // 字母线程(实现Runnable接口) class LetterRunnable implements Runnable { private final Object lock; private int count = 0; public LetterRunnable(Object lock) { this.lock = lock; } @Override public void run() { synchronized (lock) { while (count < 100) { System.out.print((char) ('A' + (count % 26))); // 循环输出A-Z count++; lock.notifyAll(); try { if (count < 100) lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } lock.notifyAll(); // 确保唤醒最后等待的线程 } } } // 测试类 public class Main { public static void main(String[] args) { Object lock = new Object(); new NumberThread(lock).start(); new Thread(new LetterRunnable(lock)).start(); } } ``` ### 关键点说明 1. **同步控制**:使用`synchronized`代码块保证原子操作[^1] 2. **线程通信**:通过`wait()`释放锁并等待,`notifyAll()`唤醒其他线程[^2] 3. **循环逻辑**:`count % 26`实现1-26和A-Z的循环输出 4. **终止条件**:`while (count < 100)`控制每个线程输出100次 ### 执行结果示例 ``` 1A2B3C4D...25Y26Z1A2B... ``` ### 注意事项 1. 必须使用同一个锁对象才能实现同步控制 2. 最后需要调用`notifyAll()`防止线程无限等待 3. 输出顺序可能受线程调度影响,但能保证交替执行
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值