深入浅出多线程(六)之两个线程交替打印奇偶数

1,549 阅读2分钟

这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战

前言

经过了前面几期的学习(划水),对于多线程并发编程也算有点概念了,当然了对于实战虽然有点距离,但是应付下面试题,是可以的了。至少从线程的创建→关闭都能答出来哈哈哈哈哈哈~
言归正传,多线程可不止口头问的,如果有笔试可能还需要手撕代码,这就需要熟练掌握,并拿捏好其中的加分点了。

拓海.jpg

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

一般我们在笔试的时候 ,最后几道可能是手撕算法题。或者直接白纸撸代码,题目可能不会很复杂,毕竟直接考验的就是你的代码功底。当然了,碰到相同相似题目的概率也是极大的~

方法一 :利用synchronized通信实现线程的交替

  • 定义两个线程,同步机制获取锁
  • 判断奇偶数,用位运算(取最后一位,与1 位运算,如果为0则为偶数,为1则为奇数),取代 count % 2 == 0(重点加分!!!!)

private static Integer count = 0;
private static final Object lock = new Object() ;

public static void main(String[] args) throws InterruptedException {
    /**
     * 利用synchronized通信实现线程的交替
     */
    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() 方法,实现交替

  • 定义一个类实现Runnable接口,重写run方法
  • 获取锁之后,直接打印输出,不需要校验
  • 唤醒该锁资源,并释放当前线程资源
  • main方法定义两个线程,因为首次为0,所以第一个线程为偶线程,以防万一,可以启动第一个线程后,主线程睡眠等待偶线程启动完成

private static Integer count = 0;
private static final Object lock = new Object() ;


static class WaitNotify implements Runnable{

    @Override
    public void run() {
        while (count<=100){
            synchronized (lock){
                System.out.println(Thread.currentThread().getName()+"打印出"+(count++));
                lock.notify();
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

public static void main(String[] args) throws InterruptedException {
    Thread thread1 = new Thread(new WaitNotify(),"偶数");
    thread1.start();
    Thread.sleep(10);
    Thread thread2 = new Thread(new WaitNotify(),"奇数");
    thread2.start();

}

小总结

  • 对于两个方法来说,方法二肯定是优于方法一的;(wait()/notify() > synchronized)
  • synchronized 通信,有加分点,用 位运算(count & 1) 取代 取余(count % 2) ,但是也有不足之处;
    资源抢夺的时候,两个线程不一定交替,有可能偶线程执行完后,往后的多次依然被偶线程抢夺到资源去执行,虽然其中有校验,对结果不影响,但是造成了多次的无用执行。
  • 用wait() 和 notify() 方法,不需要过多关注哪一个线程为奇偶线程,只需要 先执行,即为 偶线程;
    一个线程结束运行释放并唤醒其他线程,即可满足当前需求,且无过多无用操作。