juc

61 阅读2分钟

在Java中,实现多线程的并发输出(如交替输出字符"A"和"B")可以通过多种方式。下面列出了至少四种不同的解决方案,每种方案都能确保线程1仅输出"A",线程2仅输出"B",并且按照ABABABAB的顺序交替输出。

解决方案 1:使用 wait()notify()

public class ABPrint {
    private static final Object lock = new Object();
    private static int count = 0;

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            while (count < 8) {
                synchronized (lock) {
                    // 输出A
                    System.out.print("A");
                    count++;
                    lock.notify(); // 唤醒线程2
                    try {
                        if (count < 8) {
                            lock.wait(); // 让出锁,等待线程2
                        }
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        });

        Thread t2 = new Thread(() -> {
            while (count < 8) {
                synchronized (lock) {
                    // 输出B
                    System.out.print("B");
                    count++;
                    lock.notify(); // 唤醒线程1
                    try {
                        if (count < 8) {
                            lock.wait(); // 让出锁,等待线程1
                        }
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        });

        t1.start();
        t2.start();
    }
}

解决方案 2:使用 CountDownLatch

import java.util.concurrent.CountDownLatch;
public class CountdownLatchExample {
    public static void main(String[] args) {
        // Create latches for coordinating the two threads
        CountDownLatch latchA = new CountDownLatch(0); // Starts with 0 so "a" can print first
        CountDownLatch latchB = new CountDownLatch(1); // Starts with 1 to wait "b"

        // Thread to print "a"
        Thread threadA = new Thread(() -> {
            try {
                for (int i = 0; i < 5; i++) { // Adjust the loop count for the desired number of "abab" repetitions
                    latchA.await(); // Wait for latchA to be zero
                    System.out.print("a");
                    latchA = new CountDownLatch(1); // Reset latchA
                    latchB.countDown(); // Allow threadB to proceed
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // Thread to print "b"
        Thread threadB = new Thread(() -> {
            try {
                for (int i = 0; i < 5; i++) { // Adjust the loop count for the desired number of "abab" repetitions
                    latchB.await(); // Wait for latchB to be zero
                    System.out.print("b");
                    latchB = new CountDownLatch(1); // Reset latchB
                    latchA.countDown(); // Allow threadA to proceed
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // Start both threads
        threadA.start();
        threadB.start();

        // Wait for both threads to finish
        try {
            threadA.join();
            threadB.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

解决方案 3:使用 Semaphore

import java.util.concurrent.Semaphore;

public class ABPrint {
    public static void main(String[] args) {
        Semaphore semaphoreA = new Semaphore(1);
        Semaphore semaphoreB = new Semaphore(0);

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 4; i++) {
                try {
                    semaphoreA.acquire(); // 获取信号量A
                    System.out.print("A");
                    semaphoreB.release(); // 释放信号量B
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 4; i++) {
                try {
                    semaphoreB.acquire(); // 获取信号量B
                    System.out.print("B");
                    semaphoreA.release(); // 释放信号量A
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        t1.start();
        t2.start();
    }
}

解决方案 4:使用 ReentrantLockCondition

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

public class ABPrint {
    private static final Lock lock = new ReentrantLock();
    private static final Condition conditionA = lock.newCondition();
    private static final Condition conditionB = lock.newCondition();
    private static int count = 0;

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            while (count < 8) {
                lock.lock();
                try {
                    System.out.print("A");
                    count++;
                    conditionB.signal(); // 唤醒线程2
                    if (count < 8) {
                        conditionA.await(); // 等待线程2
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    lock.unlock();
                }
            }
        });

        Thread t2 = new Thread(() -> {
            while (count < 8) {
                lock.lock();
                try {
                    conditionB.await(); // 等待线程1
                    System.out.print("B");
                    count++;
                    conditionA.signal(); // 唤醒线程1
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    lock.unlock();
                }
            }
        });

        t1.start();
        t2.start();
    }
}

总结

以上四种解决方案利用不同的并发机制实现了在多线程环境下交替输出"A"和"B"的功能。每种方法都有其特点和适用场景,可以根据具体需求选择合适的实现方式。