天天看点

实现两个线程交替打印0~100的奇偶数

问题描述

有两个线程,一个线程只打印奇数,一个线程只打印偶数,而且要按照顺序打印,就是说要按照这样的方式打印:

偶线程:0

奇线程:1

偶线程:2

奇线程:3

方案一:使用synchronized关键字

要点:

  • 创建两个线程,一个线程处理偶数,一个线程处理奇数
  • 两个线程之间通过synchronized进行同步,保证count++每次只有一个线程进行操作
  • 为什么两个线程能交替执行,这里很巧的是

    count从0123自增过程就是一个奇偶数交替的过程

    ,实际上两个线程都是在不停的尝试(while循环)进入synchronized代码块,如果满足相对应的条件(偶数或是奇数)就打印输出。
public class WaitNotifyPrintOddEvenSyn {

    private static int count;

    private static final Object lock = new Object();

    /**
     * 新建2个线程,第一个只处理偶数,第二个只处理奇数(用位运算);用synchronized来通信
     */
    public static void main(String[] args) {
        new Thread(() -> {
            while (count < 100) {
                synchronized (lock) {
                    if ((count & 1) == 0) {
                        System.out.println(Thread.currentThread().getName() + ":" + count++);
                    }
                }
            }
        }, "偶线程").start();

        new Thread(() -> {
            while (count < 100) {
                synchronized (lock) {
                    if ((count & 1) == 1) {
                        System.out.println(Thread.currentThread().getName() + ":" + count++);
                    }
                }
            }
        }, "奇线程").start();
    }
}
           

方案二:使用wait/notify关键字(推荐)

要点:

  • 这个相对于上面那个好理解很多,直接走流程,偶数线程拿到锁打印输出同时count++,然后进行休眠,因为

    wait()方法的特性,休眠的同时会释放monitor锁

    ,奇数线程就可以进来了,进来后打印输出,同时notify唤醒偶数线程继续下一轮,奇数线程往下执行wait方法休眠,就这样,偶数线程唤醒奇数线程,奇数线程唤醒偶数线程,直到满足count<100条件后,线程不再休眠,直接退出程序。
  • 这个要点一个在于

    wait/notify的等待唤醒机制

    ,一个在于wait()方法的特性,休眠后会释放锁。
  • 这种方式和上面那种方式不同点在于,这种方式是

    被动唤醒的机制

    ,而上面那个是线程不断重试的机制(一直while重试,直到满足条件就打印),很明显这种方式优于上面那种!
public class WaitNotifyPrintOddEveWait {

    private static int count = 0;

    private static final Object lock = new Object();

    public static void main(String[] args) {
        new Thread(new TurningRunner(), "偶线程").start();
        new Thread(new TurningRunner(), "奇线程").start();
    }

    /**
     * 1. 拿到锁,立刻打印
     * 2. 打印完,唤醒其他线程,自己就休眠
     */
    static class TurningRunner implements Runnable {

        @Override
        public void run() {
            while (count < 100) {
                synchronized (lock) {
                    //拿到锁就打印
                    System.out.println(Thread.currentThread().getName() + ":" + count++);
                    lock.notify();
                    if (count < 100) {
                        try {
                            //如果任务还没结束,就让出当前的锁,并休眠
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}
           

方案三:可以使用ReentrantLock,设置为公平锁,即等待时间越长的线程先执行

笔记来源:慕课网悟空老师视频《Java并发核心知识体系精讲》

继续阅读