• 实现两条线程交替打印奇偶数的两种简单方法


    实现两条线程交替打印奇偶数的两种简单方法

    使用Synchronized

    public class Main {
    
        private int count = 0;
    
        public static void main(String[] args) throws InterruptedException {
            Main main = new Main();
            new Thread(()->{
                for (int i = 0; i < 50; i++) {
                    try {
                        main.printEven();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"A").start();
    
            new Thread(()->{
                for (int i = 0; i < 50; i++) {
                    try {
                        main.printOdd();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"B").start();
        }
    	
       	//打印奇数方法
        public  synchronized void printOdd() throws InterruptedException {
            while (this.count % 2 == 0) {//如果是偶数,则阻塞,释放锁
                this.wait();
            }
            System.out.println(Thread.currentThread().getName() + this.count++);
            this.notifyAll();//唤醒阻塞线程
        }
    	
        //打印偶数方法
        public  synchronized void printEven() throws InterruptedException {
            while (this.count % 2 != 0) {//如果是奇数,则阻塞,释放锁
                this.wait();
            }
            System.out.println(Thread.currentThread().getName() + this.count++);
            this.notifyAll();//唤醒阻塞线程
        }
    }
    

    此方法不容易扩展到多条线程,越多的线程在唤醒时会经历越多的竞争,加大CPU资源浪费,同时也增加耗时

    使用ReetrantLock+Condition实现精准唤醒

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Turning {
    
        public static void main(String[] args) throws InterruptedException {
            Turning turning = new Turning();
            new Thread(()->{
                for (int i = 0; i < 50; i++) {
                    turning.printO();
                }
            },"A").start();
            Thread.sleep(1000);
            new Thread(()->{
                for (int i = 0; i < 50; i++) {
                    turning.printJ();
                }
            },"B").start();
        }
    
        private ReentrantLock lock = new ReentrantLock();
        private Condition condition1 = lock.newCondition();
        private Condition condition2 = lock.newCondition();
    
        private int number = 0;
    
        public void printJ() {
            lock.lock();
            try {
                while (number % 2 == 0) {
                    condition1.await(); //如果是偶数,在此处阻塞
                }
                System.out.println(Thread.currentThread().getName()+number++);
                condition2.signal(); //唤醒在2处阻塞的线程
            }catch (Exception e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    
        public void printO() {
            lock.lock();
            try{
                while (number % 2 != 0) { 
                    condition2.await(); //如果是奇数,在此处阻塞
                }
                System.out.println(Thread.currentThread().getName()+number++);
                condition1.signal(); //唤醒在1处阻塞的线程
            }catch (Exception e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    }
    

    此方法容易扩展到多条线程交替,且为精准唤醒,减少线程竞争带来的消耗

  • 相关阅读:
    java项目配置域名(tomcat直接配置 or 使用nginx反向代理)
    java爬虫学习
    python爬虫
    log4j的日志级别(ssm中log4j的配置)
    Python中list,tuple,dict,set的区别和用法
    [转]C# Eval在asp.net中的用法及作用
    【转】一个运维经理的运维经验总结
    [转]使用 LVS 实现负载均衡原理及安装配置详解
    [转]33个网站足以使你成为一个天才
    搜狐邮箱想说爱你不容易!
  • 原文地址:https://www.cnblogs.com/dwwzone/p/13291464.html
Copyright © 2020-2023  润新知