Java并发编程:两个线程交替打印0

编程入门 行业动态 更新时间:2024-10-11 19:20:11

Java并发编程:两个<a href=https://www.elefans.com/category/jswz/34/1771240.html style=线程交替打印0"/>

Java并发编程:两个线程交替打印0

问题描述:两个线程交替打印输出数字0~100,一个线程只打印偶数,另一个只打印奇数

方案一:使用synchronized关键字

  • 创建两个线程,一个线程处理偶数,一个线程处理奇数,两个线程之间通过synchronized进行同步,保证count++每次只有一个线程进行操作

  • 为什么两个线程能交替执行,这里很巧的是count从0123...自增过程就是一个奇偶数交替的过程,实际上两个线程都是在不停的尝试(while循环)进入synchronized代码块,如果满足相对应的条件(偶数或是奇数)就打印输出。

package com.hs.demo.code;/*** 两个线程交替打印0~100的奇偶数,用synchroized关键字实现** 这种写法有很多多余操作.就是同一个线程会出现多次抢到了锁,但是不满足条件跳过了if语句并不会执行 * count++,这种写法效率并不高效*/
public class SynchroizedPrintOddEven
{private static int count;//临界资源private static  final Object lock = new Object();//新建两个线程,第1个只处理偶数,第二个只处理奇数(用位运算),用synchronized来通讯public static void main(String[] args){new Thread(new Runnable() {@Overridepublic void run() {while (count < 100){synchronized (lock){//count & 1 一个数字把它和1做位与的操作,1再二进制就是1,count转换位二进制,和1去与,就是取出count二进制的最低位,最低位是1代表奇数,0代表是偶数,比count%2 == 0 效率高//因为线程是随机抢锁的,可能会出现同一个线程多次进入,但是不满足条件,并不会执行count++.if((count & 1) == 0){System.out.println(Thread.currentThread().getName() + ":" + count++);}}}}},"偶数").start();new Thread(new Runnable() {@Overridepublic void run() {while (count < 100){synchronized (lock){//count & 1 一个数字把它和1做位与的操作,1再二进制就是1,count转换位二进制,和1去与,就是取出count二进制的最低位,最低位是1代表奇数,0代表是偶数,比count%2 == 0 效率高if((count & 1) == 1){System.out.println(Thread.currentThread().getName() + ":" + count++);}}}}},"奇数").start();}
}

输出结果:

 结果看起来没问题,奇偶数有交替运行。但实际上并不代表着这两个线程在交替运行,因为线程是随机抢锁的,有可能连续十次都是偶数线程好运抢到了锁,只是因为不满足条件,没有对 count 进行 +1,白白浪费一次占用资源的机会。

因此,这种方式虽然能实现,但存在资源浪费,只需要在两个线程拿到锁时输出语句,即可看到存在大量的资源浪费。


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

  • 这个相对于上面那个好理解很多,直接走流程,偶数线程拿到锁打印输出同时count++,然后进行休眠,因为wait()方法的特性,休眠的同时会释放monitor锁,奇数线程就可以进来了,进来后打印输出,同时notify唤醒偶数线程继续下一轮,奇数线程往下执行wait方法休眠,就这样,偶数线程唤醒奇数线程,奇数线程唤醒偶数线程,直到满足count<100条件后,线程不再休眠,直接退出程序。

  • 这个要点一个在于wait/notify的等待唤醒机制,一个在于wait()方法的特性,休眠后会释放锁。

  • 这种方式和上面那种方式不同点在于,这种方式是被动唤醒的机制,而上面那个是线程不断重试的机制(一直while重试,直到满足条件就打印),很明显这种方式优于上面那种!

public class WaitNotifyPrintOddEven
{private static int count = 0;//当前线程必须拥有此对象的锁,才能调用某个对象的wait()方法能让当前线程阻塞,private static final Object lock = new Object();public static void main(String[] args){new Thread(new TurningRunner(),"偶数").start();new Thread(new TurningRunner(),"奇数").start();}//拿到锁,我们就打印,一旦打印完唤醒其他线程就休眠static  class TurningRunner implements Runnable{@Overridepublic 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();}}}}}}
}

输出结果: 

这种方式,每次抢到资源都是有意义的,效率更高


Java并发编程-两个线程交替打印0-100的奇偶数

聊聊并发编程的10个坑

更多推荐

Java并发编程:两个线程交替打印0

本文发布于:2024-02-10 22:36:22,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1677704.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:线程   两个   Java

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!