多线程轮流打印字符

要求:使用多个线程轮流打印字符

  1. 方法1。无锁自旋,一般在多核机器并且临界区耗时很短的话可以尝试自旋
public class printABC {
    static Logger log = new Logger(Logger.LogLevel.DEBUG, printABC.class);
    static volatile int cur = 0;
    public static void main(String[] args) {
        String[] strings = {"A", "B", "C"};
        int n = strings.length;
        int printCnt = 100;
        int cnt = n * printCnt;
        for (int i = 0; i < n; i++) {
            int j = i;
            new Thread(() -> {
                while (cur < cnt) {
                    if (cur % n == j && cur < cnt) {
                        log.info(cur / n + " - " + strings[j]);
                        cur++;
                    }
                }
            }).start();
        }
    }
}
  1. 方法2。使用 ReentrantLock
public class printABC {
    static Logger log = new Logger(Logger.LogLevel.DEBUG, printABC.class);
    static volatile int cur = 0;
    static final ReentrantLock lock = new ReentrantLock();
    static Condition condition = lock.newCondition();

    public static void main(String[] args) {
        String[] strings = {"A", "B", "C"};
        int n = strings.length;
        int printCnt = 100;
        int cnt = n * printCnt;
        for (int i = 0; i < n; i++) {
            int j = i;
            new Thread(() -> {
                while (cur < cnt) {
                    lock.lock();
                    try {
                        if (cur % n == j && cur < cnt) {
                            log.info(cur / n + " - " + strings[j]);
                            cur++;
                            condition.signalAll();
                        }else{
                            condition.await();
                        }
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    } finally {
                        lock.unlock();
                    }
                }
            }).start();
        }
    }
}
  1. 方法3。使用 synchronized
public class printABC {
    static Logger log = new Logger(Logger.LogLevel.DEBUG, printABC.class);
    static volatile int cur = 0;
    static final ReentrantLock lock = new ReentrantLock();
    public static void main(String[] args) {
        String[] strings = {"A", "B", "C"};
        int n = strings.length;
        int printCnt = 100;
        int cnt = n * printCnt;
        for (int i = 0; i < n; i++) {
            int j = i;
            new Thread(() -> {
                while (cur < cnt) {
                    synchronized (lock) {
                        if (cur % n == j && cur < cnt) {
                            log.info(cur / n + " - " + strings[j]);
                            cur++;
                            lock.notifyAll();
                        } else {
                            try {
                                lock.wait();
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                        }
                    }
                }
            }).start();
        }
    }
}

对于初学者来说需要注意的点:

  1. 如果使用加锁方式的话,在线程调用阻塞方法时需要先获取到锁,否则会抛异常
  2. 当线程被唤醒时需要注意虚假唤醒的情况
  3. 多线程共享变量 volatile 是一定要加的
posted @ 2024-09-08 18:28  zzzggb  阅读(8)  评论(0编辑  收藏  举报