两个线程交替打印

这是一个关于Java线程面试题的解析,题目要求两个线程轮流打印数字,线程1打印1、2、3,线程2打印4、5、6,直到达到指定数值(如100)。文章介绍了作者时隔多年后重新实现该问题的过程,以此巩固线程的有序性概念。

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

很久之前遇到的一个面试题,要求是指定一个数值(如100),线程1打印1、2、3,线程2打印4、5、6,如此反复,到指定数值(100)时程序结束,当时并没有做出来,回来之后在网上查看了些博客,也有了思路,虽然也做出来了,但并没有完全领会,今天看到线程的有序性,事隔多年,自己又动手实现了一次,也夯实了一下基础知识。话不多说,上代码  ^_^

public class ThreadAlternatePrint extends Thread{
    private Object lock;
    private static final Integer counter = 100;
    private volatile static boolean execFlag = false;
    private int printCount=0;
    private volatile static int addNumber=1;

    public ThreadAlternatePrintDemoExt(Object lock) {
        this.lock = lock;
    }
    @Override
    public void run() {
        try {
            synchronized (lock){
                while (addNumber <= counter){
                    if (!execFlag) {
                        if (addNumber > counter) {
                            return;
                        }
                        System.out.println(Thread.currentThread().getName() + " 打印 " + addNumber);
                        lock.notify();
                        printCount++;
                        addNumber++;
                        execFlag = false;
                        if (printCount == 3) {
                            execFlag = true;
                            printCount = 0;
                            lock.wait();
                        }
                    }

                    if (execFlag) {
                        if (addNumber > counter) {
                            return;
                        }
                        System.out.println(Thread.currentThread().getName() + " 打印 " + addNumber);
                        lock.notify();
                        printCount++;
                        addNumber++;
                        execFlag=true;
                        if (printCount == 3) {
                            execFlag = false;
                            printCount = 0;
                            lock.wait();
                        }
                    }
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Object lock = new Object();
        ThreadAlternatePrint t = new ThreadAlternatePrint(lock);
        ThreadAlternatePrint t1 = new ThreadAlternatePrint(lock);

        t.start();
        t1.start();
    }
}

实现的效果如下:

Thread-0 打印 1
Thread-0 打印 2
Thread-0 打印 3
Thread-1 打印 4
Thread-1 打印 5
Thread-1 打印 6
Thread-0 打印 7
Thread-0 打印 8
Thread-0 打印 9
Thread-1 打印 10
Thread-1 打印 11
Thread-1 打印 12
Thread-0 打印 13
Thread-0 打印 14
Thread-0 打印 15
Thread-1 打印 16
Thread-1 打印 17
Thread-1 打印 18
Thread-0 打印 19
Thread-0 打印 20
Thread-0 打印 21
Thread-1 打印 22
Thread-1 打印 23
Thread-1 打印 24
Thread-0 打印 25
Thread-0 打印 26
Thread-0 打印 27
Thread-1 打印 28
Thread-1 打印 29
Thread-1 打印 30
Thread-0 打印 31
Thread-0 打印 32
Thread-0 打印 33
Thread-1 打印 34
Thread-1 打印 35
Thread-1 打印 36
Thread-0 打印 37
Thread-0 打印 38
Thread-0 打印 39
Thread-1 打印 40
Thread-1 打印 41
Thread-1 打印 42
Thread-0 打印 43
Thread-0 打印 44
Thread-0 打印 45
Thread-1 打印 46
Thread-1 打印 47
Thread-1 打印 48
Thread-0 打印 49
Thread-0 打印 50
Thread-0 打印 51
Thread-1 打印 52
Thread-1 打印 53
Thread-1 打印 54
Thread-0 打印 55
Thread-0 打印 56
Thread-0 打印 57
Thread-1 打印 58
Thread-1 打印 59
Thread-1 打印 60
Thread-0 打印 61
Thread-0 打印 62
Thread-0 打印 63
Thread-1 打印 64
Thread-1 打印 65
Thread-1 打印 66
Thread-0 打印 67
Thread-0 打印 68
Thread-0 打印 69
Thread-1 打印 70
Thread-1 打印 71
Thread-1 打印 72
Thread-0 打印 73
Thread-0 打印 74
Thread-0 打印 75
Thread-1 打印 76
Thread-1 打印 77
Thread-1 打印 78
Thread-0 打印 79
Thread-0 打印 80
Thread-0 打印 81
Thread-1 打印 82
Thread-1 打印 83
Thread-1 打印 84
Thread-0 打印 85
Thread-0 打印 86
Thread-0 打印 87
Thread-1 打印 88
Thread-1 打印 89
Thread-1 打印 90
Thread-0 打印 91
Thread-0 打印 92
Thread-0 打印 93
Thread-1 打印 94
Thread-1 打印 95
Thread-1 打印 96
Thread-0 打印 97
Thread-0 打印 98
Thread-0 打印 99
Thread-1 打印 100

<think>好的,我现在需要帮助用户了解如何通过编程实现两个线程交替打印。用户已经提供了一些参考资料,包括使用Java和Python的例子,以及涉及synchronized、wait、notify等方法。我需要先整理这些信息,然后给出清晰的步骤和示例代码。 首先,用户的问题是关于两个线程交替打印的实现方法,可能是指交替打印奇偶数,或者交替打印不同的字符。根据提供的引用,常见的做法是使用线程间的同步机制,比如锁和条件变量,或者使用wait/notify来控制线程的执行顺序。 我需要考虑不同编程语言的实现,用户提供的引用中有Java和Python的例子。但用户的问题没有指定语言,可能需要给出两种语言的示例,或者选择其中一种。不过用户之前的问题可能偏向Python,因为最后的示例代码是Python的快速排序,但引用的资料中有Java和Python的例子。需要确认用户的需求,但根据问题描述,用户可能希望得到通用的方法,或者具体语言的示例。 另外,用户提到“交替打印”,可能是指两个线程轮流执行,比如一个打印奇数,一个打印偶数,或者交替打印A和B。需要明确场景,但根据引用中的例子,奇偶数交替打印比较常见。 接下来,我需要整理实现步骤。通常,实现线程交替打印需要以下步骤: 1. 创建共享对象或锁,用于线程同步。 2. 定义两个线程,每个线程负责打印特定的内容。 3. 使用同步机制确保每次只有一个线程执行打印操作。 4. 通过wait和notify(或类似机制)控制线程交替执行。 在Java中,可以使用synchronized关键字配合wait和notify,或者使用ReentrantLock和Condition。在Python中,由于GIL的存在,多线程可能不如多进程高效,但可以使用threading模块中的Lock和Condition来实现。 需要检查引用中的示例,例如引用[1]和[4]提到Java中使用synchronized和wait/notify,而引用[2]和[5]提到Python中的多线程交替打印。引用[3]提到使用Condition对象。 现在,我需要为两种语言分别给出示例代码,并解释其步骤。但用户可能希望得到一个具体的例子,比如交替打印奇偶数,或者交替打印ABAB等。 根据用户的问题,他们可能希望看到两种方法的对比,比如使用synchronized和wait/notify的方法,或者使用Lock和Condition的方法。需要参考提供的引用,例如引用[4]中的实现方式,以及引用[3]中的Condition用法。 在Java中,基本的实现步骤是: - 共享一个锁对象。 - 线程1获取锁后,检查条件是否满足(如是否是偶数),满足则打印并递增,然后唤醒另一个线程,否则等待。 - 线程2类似,检查是否是奇数,打印后唤醒另一个线程。 在Python中,由于没有内置的wait/notify机制,可以使用threading.Condition来实现类似的功能。或者使用Event对象。 需要注意的是,在Python中,多线程由于GIL的关系,可能不会真正并行执行,但交替打印可以通过同步机制实现。 另外,需要考虑线程启动的顺序,可能需要一个标志变量来确定当前应该由哪个线程执行。 现在,需要编写示例代码。例如,在Java中,使用synchronized的代码可能如下: class Shared { int count = 1; boolean isOdd = true; } 线程1(奇数线程): synchronized (shared) { while (shared.count <= max) { if (shared.isOdd) { print; shared.count++; shared.isOdd = false; shared.notify(); } else { shared.wait(); } } } 线程2(偶数线程)类似,检查isOdd是否为false。 在Python中,可以使用threading.Condition: import threading class Shared: def __init__(self): self.count = 1 self.cond = threading.Condition() self.is_odd = True def print_odd(shared, max): with shared.cond: while shared.count <= max: if shared.is_odd: print(shared.count) shared.count +=1 shared.is_odd = False shared.cond.notify() else: shared.cond.wait() def print_even(shared, max): with shared.cond: while shared.count <= max: if not shared.is_odd: print(shared.count) shared.count +=1 shared.is_odd = True shared.cond.notify() else: shared.cond.wait() 然后创建两个线程,启动它们。 不过需要确保线程正确退出,否则可能出现无法结束的情况,如引用[5]中提到的问题,可能需要检查条件是否满足,并在适当的时候退出循环。 还需要考虑最大次数,比如打印到10为止。 另外,在Python中,由于线程可能因为wait而阻塞,需要确保在count超过max时,线程能够退出循环。 例如,在print_odd函数中: while shared.count <= max: if ...: ... else: shared.cond.wait() 但如果在等待时,count已经超过max,线程可能无法退出。因此,可能需要使用带有超时的wait,或者在notify时确保所有线程都能被唤醒。或者,在循环条件中不仅要检查count是否超过max,还要处理被唤醒后的状态。 这可能需要更复杂的条件判断。 另外,在Java中,使用两个Condition对象可能更高效,如引用[3]提到的,每个线程有自己的Condition,这样在唤醒时只唤醒另一个线程,而不是所有等待的线程,避免虚假唤醒。 综上,我需要整理出两种实现方法:使用synchronized和wait/notify,以及使用Lock和Condition(可能更高效)。然后给出Java和Python的示例代码,并解释每个步骤。 在回答中,需要结构清晰,分步骤说明,并确保代码正确,避免死锁或无法退出的情况。同时,需要引用提供的参考资料,例如引用[1]、[3]、[4]中的方法。</think>### 两个线程交替打印的实现方法 实现两个线程交替打印的核心在于**线程同步**和**条件判断**。以下是两种常见实现方式的详细步骤及示例代码: --- ### 方法一:使用`synchronized`和`wait/notify`(Java) 通过共享对象的锁机制,控制线程交替执行。 #### 实现步骤: 1. **定义共享对象**:存储当前打印的数值和线程状态。 2. **线程1打印奇数**:检查当前数值是否为奇数,满足则打印并唤醒线程2,否则等待。 3. **线程2打印偶数**:检查当前数值是否为偶数,满足则打印并唤醒线程1,否则等待。 ```java public class AlternatePrint { private static final Object lock = new Object(); private static int count = 1; private static final int MAX = 10; public static void main(String[] args) { new Thread(() -> { synchronized (lock) { while (count <= MAX) { if (count % 2 == 1) { System.out.println("Thread 1: " + count++); lock.notify(); // 唤醒线程2 } else { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }).start(); new Thread(() -> { synchronized (lock) { while (count <= MAX) { if (count % 2 == 0) { System.out.println("Thread 2: " + count++); lock.notify(); // 唤醒线程1 } else { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }).start(); } } ``` **关键点**: - `wait()`释放锁并进入等待状态,`notify()`唤醒其他线程[^4]。 - 必须使用循环检查条件,避免虚假唤醒[^5]。 --- ### 方法二:使用`Condition`和`ReentrantLock`(Java) 通过更细粒度的锁控制,减少不必要的唤醒。 #### 实现步骤: 1. **定义锁和条件变量**:每个线程关联一个`Condition`。 2. **交替触发条件**:奇数线程完成后触发偶数线程的条件,反之亦然。 ```java import java.util.concurrent.locks.*; public class AlternatePrintWithCondition { private static ReentrantLock lock = new ReentrantLock(); private static Condition oddCondition = lock.newCondition(); private static Condition evenCondition = lock.newCondition(); private static int count = 1; private static final int MAX = 10; public static void main(String[] args) { new Thread(() -> { lock.lock(); try { while (count <= MAX) { if (count % 2 == 1) { System.out.println("Thread 1: " + count++); evenCondition.signal(); // 通知偶数线程 } else { oddCondition.await(); } } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }).start(); new Thread(() -> { lock.lock(); try { while (count <= MAX) { if (count % 2 == 0) { System.out.println("Thread 2: " + count++); oddCondition.signal(); // 通知奇数线程 } else { evenCondition.await(); } } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }).start(); } } ``` **关键点**: - 每个线程通过`Condition.await()`等待,通过`Condition.signal()`精准唤醒目标线程[^3]。 - 避免全局锁竞争,提升效率。 --- ### 方法三:使用`threading.Condition`(Python) Python中通过条件变量实现类似逻辑。 ```python import threading class SharedState: def __init__(self): self.count = 1 self.cond = threading.Condition() self.is_odd = True def print_odd(shared, max_count): with shared.cond: while shared.count <= max_count: if shared.is_odd: print(f"Thread 1: {shared.count}") shared.count += 1 shared.is_odd = False shared.cond.notify() else: shared.cond.wait() def print_even(shared, max_count): with shared.cond: while shared.count <= max_count: if not shared.is_odd: print(f"Thread 2: {shared.count}") shared.count += 1 shared.is_odd = True shared.cond.notify() else: shared.cond.wait() shared = SharedState() max_num = 10 t1 = threading.Thread(target=print_odd, args=(shared, max_num)) t2 = threading.Thread(target=print_even, args=(shared, max_num)) t1.start() t2.start() t1.join() t2.join() ``` **关键点**: - `with shared.cond`自动获取和释放锁。 - `notify()`唤醒等待的线程,`wait()`释放锁并阻塞[^2]。 --- ### 对比分析 | 方法 | 优点 | 缺点 | |----------------|-------------------------------|------------------------------| | `synchronized` | 代码简单,无需额外依赖 | 唤醒不精准,可能产生竞争 | | `Condition` | 精准唤醒,减少锁竞争 | 代码复杂度稍高 | | Python实现 | 语法简洁,适合轻量级任务 | 因GIL限制,不适合CPU密集型任务 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值