zoukankan      html  css  js  c++  java
  • Java多线程系列之:线程间的通信

    一,线程间的协作,如何来实现?

    1,轮询:难以保证及时性,资源开销很大

    2,等待和通知

    等待和通知的标准范式:

      等待方:
        要去获取对象的锁,
        然后在循环里判断条件是否满足,不满足调用wait方法。
        条件满足,执行业务逻辑
      通知方:
        获取对象的锁
        改变条件
        通知所有等待在对象的线程

    3,方法:

      wait():等待着获取对象的锁
      wait(1000):等待超时,超过一定时间就不等待了。
      notify:通知一个线程
      notifyAll:通知所有等待同一把锁的线程

    二,join()方法
    1,面试问题:有线程A和线程B,如何保证线程B一定在线程A执行完以后才执行?
      方法一:join()
      方法二:countDownLatch
    解释:如果线程A执行了线程B的join方法,线程A必须等待线程B执行完了以后,线程A才能继续自己的工作。

    示例代码:掉用join()方法,可以让该线程优先执行

    /**
     * 演示join()方法
     */
    public class UseJoin2 {
    
        static class JumpQueue extends Thread{
            @Override
            public void run() {
                for (int i = 0; i <5 ; i++) {
                    System.out.println("当前线程正在执行步骤"+i);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        public static void main(String[] args) {
    
            System.out.println("进入main方法------>");
    
            JumpQueue jumpQueue = new JumpQueue();
            jumpQueue.setName("joinThread");
            jumpQueue.start();
    
            //jumpQueue.join()方法:会让jumpQueue线程在main线程之前执行
            try {
                jumpQueue.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println("main线程开始处理业务逻辑");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("main线程处理完业务逻辑了");
    
        }
    }

    三,yield(),sleep(),wait(),notify()等方法对锁的影响
      线程在执行yield()以后,持有的锁是不释放的
      sleep()方法调用以后,持有的锁是不释放的
      wait():在调用wait()方法之前,必须要持有锁。在调用wait()方法以后。锁就会被释放(虚拟机进行释放),当wait方法返回时,线程会重新持有锁
      notify():在调用之前,必须要持有锁。调用notify()方法本身是不会释放锁的,只有synchronized代码块执行完才释放锁
      notifyAll():同notify()
    比如:public synchronized void changeKm(){
        this.km = 101;
        notify();//当执行完这行代码时,此时还没有释放锁。
        System.out.println("处理业务逻辑"); //执行完这一行代码后,才释放锁。
       }

    1,示例代码:sleep()方法调用以后,持有的锁识是不释放的

    /**
     * 验证sleep()方法,线程休眠时不会释放锁
     * 当A线程拿到锁后,然后进行sleep休眠。其他线程是拿不到锁的,只能等待
     */
    public class SleepLock {
    
        private Object lock = new Object();
    
        //会休眠的线程类
        private class ThreadSleep extends Thread{
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                //尝试去拿锁
                System.out.println(threadName + " try to take the lock");
                try {
                    synchronized (lock){
                        System.out.println(threadName + " is taking the lock");
                        //该线程拿到锁后,休眠5秒
                        Thread.sleep(5000);
                        System.out.println("Finish the work: "+ threadName);
                    }
                }catch (InterruptedException e){
                }
            }
        }
    
        //不会休眠的线程类
        private class ThreadNotSleep extends Thread{
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                //尝试去拿锁
                System.out.println(threadName + " try to take the lock time = "+System.currentTimeMillis());
                synchronized (lock){
                    System.out.println(threadName + " taking the lock time = "+ System.currentTimeMillis());
                    System.out.println("Finish the work"+threadName);
                }
            }
        }
    
        public static void main(String[] args) {
    
            SleepLock sleepLock = new SleepLock();
    
            //会休眠的线程
            Thread threadSleep = sleepLock.new ThreadSleep();
            threadSleep.setName("threadSleep");
            
            //不会休眠的线程
            Thread threadNotSleep = sleepLock.new ThreadNotSleep();
            threadNotSleep.setName("threadNotSleep");
    
            threadSleep.start();
            threadNotSleep.start();
        }
    }

    2,示例代码:wait()方法调用后,会释放锁

    public class ThreadDomain31 extends Thread{
        private Object lock;
    
        public ThreadDomain31(Object object){
            this.lock = object;
        }
        @Override
        public void run() {
            try {
                synchronized (lock)
                {
                    System.out.println(Thread.currentThread().getName() + " Begin wait()");
                    lock.wait();
                    System.out.println(Thread.currentThread().getName() + " End wait");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public class Test {
        public static void main(String[] args) {
            /**
             * 输出:
             *  Thread-0 Begin wait()
                Thread-1 Begin wait()
                wait()会释放锁,不然线程2根本进不去
             */
            Object lock = new Object();
            ThreadDomain31 mt0 = new ThreadDomain31(lock);
            ThreadDomain31 mt1 = new ThreadDomain31(lock);
            mt0.start();
            mt1.start();
        }
    }

    3,经典的生产者消费者模式演示 :wait()/notify()方法的使用

    /**
     * 产品
     */
    public class Product {
    
        private String name;
        private boolean flag = false;
    
        //生产方法
        public synchronized void set(String name){
    
            System.out.println(Thread.currentThread().getName()+"准备生产数据.....");
    
            //如果有值就等待
            if (this.flag){
                try {
                    System.out.println("数据还没有被消费,生产者进行等待");
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+"开始生产数据...");
            Random random = new Random();
            int second = random.nextInt(5000);
            try {
                Thread.sleep(second);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.name = name;
            this.flag = true;
            System.out.println(Thread.currentThread().getName()+"生产数据完成..."+",一共花费了"+second+"ms");
            System.out.println(Thread.currentThread().getName()+"通知消费者去消费数据");
            this.notify();//通知消费者去消费
        }
        //消费方法
        public synchronized void get(){
            System.out.println(Thread.currentThread().getName()+"准备消费数据.....");
            //如果没有等待
            if (!this.flag){
                try {
                    System.out.println("数据还没有被生产,消费者进行等待");
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+"开始消费数据...");
            Random random = new Random();
            int second = random.nextInt(5000);
            try {
                Thread.sleep(second);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"消费数据完成..."+"name:"+name+""+",一共花费了"+second+"ms");
            this.flag = false;
            System.out.println(Thread.currentThread().getName()+"通知生产者去生产数据");
            this.notify();//通知生产者去生产
        }
    }
    /**
     * 生产者
     */
    public class Producer implements Runnable{
    
        private Product student;
        public Producer(Product student){
            this.student = student;
        }
        @Override
        public void run() {
            while (true){
                student.set("产品名称");
            }
        }
    }
    /**
     * 消费者
     */
    public class Consumer implements Runnable{
    
        private Product student;
        public Consumer(Product student){
            this.student = student;
        }
        @Override
        public void run() {
            while (true){
                student.get();
            }
        }
    }
  • 相关阅读:
    记录一些常用的JS属性和语句
    明确前端工作定位
    PHP实现定时执行任务的方法
    经典的阿里前端笔试题
    CSS3 一、文本阴影textshadow属性
    Javascript作用域
    DOM事件探秘
    JavaScript中‘this’关键词的优雅解释
    Sublime Text3 支持Less
    修改table 设置默认值
  • 原文地址:https://www.cnblogs.com/inspred/p/11102480.html
Copyright © 2011-2022 走看看