使用两个线程交替打印0-100的奇偶数

2022/1/10 Thread多线程

本篇是在学习5.Thread和Object中线程相关的重要方法 (ladybug.top) (opens new window)时对notify()wait()的相关用法记录。

# 方法一:使用同步锁

public class PrintNumberWithTwoThread {
    private static final Object lock = new Object();
    private static int i = 0;
    public static void main(String[] args) throws InterruptedException {
        Thread1 thread1 = new Thread1();

        Thread2 thread2 = new Thread2();

        thread1.start();

        thread2.start();
    }

    static class Thread1 extends Thread {
        @Override
        public void run() {
            while (i < 100) {
                synchronized (lock) {
                    if ((i & 1) == 1) {
                        System.out.println("线程" + Thread.currentThread().getName() + ":" + i++);
                    }
                }
                // 打印出来就会发现进行了多次无效的循环
                // System.out.println("进入循环");
            }
        }
    }

    static class Thread2 extends Thread {

        @Override
        public void run() {
            while (i < 100) {
                synchronized (lock) {
                    if ((i & 1) == 0) {
                        System.out.println("线程" + Thread.currentThread().getName() + ":" + i++);
                    }
                }
                // System.out.println("进入循环");
            }
        }
    }
}

使用这种方法效率较低,会多次进入循环争夺锁。比如Thread2如果一直持有lock就会一直循环下去,变量不增加循环就不会结束,一直到另一个线程Thread1争夺到lock锁,以此反复,最终变量i自增到100,两个线程都结束循环,程序结束。

# 方法二:使用notify()wait()

public class PrintNumberWithTwoThread2 {
    private static final Object lock = new Object();
    private static int i = 0;

    public static void main(String[] args) throws InterruptedException {
        Target target = new Target();
        Thread thread1 = new Thread(target,"偶数");
        Thread thread2 = new Thread(target,"奇数");
        thread1.start();
        // 先让偶数线程启动
        Thread.sleep(100);
        thread2.start();
    }

    static class Target implements Runnable{
        @Override
        public void run() {
            while (i <= 100) {
                synchronized (lock) {
                    System.out.println("线程" + Thread.currentThread().getName() + ":" + i++);
                    lock.notify();
                    if (i <= 100) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}

使用这种方式比方法一要好得多。线程启动后获取到lock锁,开始打印数据,打印后调用notify()通知另一个线程,本线程因为调用wait()方法进入"Waiting"状态并释放锁,另一个线程获取锁,打印数据,调用notify()通知另一个线程,以此反复完成变量i自增到100结束线程。