• 线程之间的通信


    主要是三个方法wait(); notify(); notifyAll()

    wait()使当前线程阻塞,前提是 必须先获得锁,一般配合synchronized 关键字使用,即,一般在synchronized 同步代码块里使用 wait()、notify/notifyAll() 方法。

    wait方法释放锁, notify方法不释放锁

    由于 wait()、notify/notifyAll() 在synchronized 代码块执行,说明当前线程一定是获取了锁的。
    当线程执行wait()方法时候,会释放当前的锁,然后让出CPU,进入等待状态。
    只有当 notify/notifyAll() 被执行时候,才会唤醒一个或多个正处于等待状态的线程,然后继续往下执行,直到执行完synchronized 代码块的代码或是中途遇到wait() ,再次释放锁。
     
    notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。notifyAll 会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现。
     
    wait(), notify(), notifyAll() 必须是同一对象的多个线程之间的通信
    举例
     
    Target1
     1 public class Target1 implements Runnable {
     2 
     3     private Demo3 demo;
     4 
     5     public Target1(Demo3 demo) {
     6         this.demo = demo;
     7     }
     8 
     9     @Override
    10     public void run() {
    11         demo.set();
    12     }
    13 
    14 }

    Target2

     1 public class Target2 implements Runnable {
     2 
     3     private Demo3 demo;
     4 
     5     public Target2(Demo3 demo) {
     6         this.demo = demo;
     7     }
     8 
     9     @Override
    10     public void run() {
    11         demo.get();
    12     }
    13 
    14 }

    Demo3

    public class Demo3 {
    
        private volatile int signal;
    
        public synchronized void set () {
            signal = 1;
            notifyAll(); // notify方法会随机叫醒一个处于wait状态的线程
            // notifyAll叫醒所有的处于wait线程,争夺到时间片的线程只有一个
            System.out.println("叫醒线程叫醒之后休眠开始...");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
        public synchronized int get () {
            System.out.println(Thread.currentThread().getName() + " 方法执行了...");
            if(signal != 1) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + " 方法执行完毕...");
            return signal;
        }
    
        public static void main(String[] args) {
    
            Demo3 d = new Demo3();
            Target1 t1 = new Target1(d);
            Target2 t2 = new Target2(d);
    
            new Thread(t2).start();
            new Thread(t2).start();
            new Thread(t2).start();
            new Thread(t2).start();
    
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(t1).start();
    
        }
    }

    Console

    hread-0 方法执行了...
    Thread-2 方法执行了...
    Thread-1 方法执行了...
    Thread-3 方法执行了...
    叫醒线程叫醒之后休眠开始...
    Thread-3 方法执行完毕...
    Thread-1 方法执行完毕...
    Thread-2 方法执行完毕...
    Thread-0 方法执行完毕...

    生产者和消费者问题

    Tmall

     1 public class Tmall {
     2     private int count;
     3 
     4     public final int MAX_COUNT = 10;
     5 
     6     public synchronized void  push(){
     7         while (count >= MAX_COUNT){
     8             try {
     9                 System.out.println(Thread.currentThread().getName()+"生产者库存数量库存满,生产者停止生产");
    10                 wait();
    11             } catch (InterruptedException e) {
    12                 e.printStackTrace();
    13             }
    14         }
    15         count++;
    16         System.out.println(Thread.currentThread().getName()+"生产者生产,当前库存为:"+count);
    17         notifyAll();
    18     }
    19 
    20 
    21 
    22     public synchronized void take(){
    23         while (count<= 0){
    24             try {
    25                 System.out.println(Thread.currentThread().getName()+"生产者库存数量库0,消费者等待");
    26                 wait();
    27             } catch (InterruptedException e) {
    28                 e.printStackTrace();
    29             }
    30         }
    31 
    32         count--;
    33         System.out.println(Thread.currentThread().getName()+"生产者消费,当前库存为:"+count);
    34         notifyAll();
    35 
    36     }

    TakeTarget

     1 public class TakeTarget implements  Runnable{
     2 
     3     private Tmall tmall;
     4 
     5     public TakeTarget(Tmall tmall){
     6         this.tmall = tmall;
     7     }
     8 
     9 
    10     @Override
    11     public void run() {
    12 
    13        while (true){
    14            tmall.take();
    15            try {
    16                Thread.sleep(1000);
    17            } catch (InterruptedException e) {
    18                e.printStackTrace();
    19            }
    20        }
    21 
    22     }
    23 }

    PushTarget

     1 public class PushTarget  implements Runnable{
     2 
     3     private Tmall tmall;
     4 
     5     public PushTarget(Tmall tmall){
     6         this.tmall = tmall;
     7     }
     8 
     9 
    10     @Override
    11     public void run() {
    12         while (true){
    13             tmall.push();
    14             try {
    15                 Thread.sleep(1000);
    16             } catch (InterruptedException e) {
    17                 e.printStackTrace();
    18             }
    19         }
    20     }
    21 }

    Main

        public static void main(String[] args) {
    
            Tmall tmall = new Tmall();
    
            PushTarget p = new PushTarget(tmall);
    
            TakeTarget t = new TakeTarget(tmall);
    
            new Thread(p).start();
            new Thread(p).start();
            new Thread(p).start();
            new Thread(p).start();
    
    
            new Thread(t).start();
            new Thread(t).start();
            new Thread(t).start();
        }
    
    }

    生产者线程多余消费者线程

    Console

    Thread-6生产者消费,当前库存为:9
    Thread-0生产者生产,当前库存为:10
    Thread-1生产者库存数量库存满,生产者停止生产..................

     
     
     
     
  • 相关阅读:
    Go语言学习之1 基本概念、环境搭建、第一个Go程序
    go环境搭建
    go 圣经阅读笔记之-入门
    RabbitMQ
    图片选择并使用base64展示
    关于c# hashtable的一个注意点
    js image to base64 摘录
    linq to sql 获取sql与参数添加到日志中
    时钟的实现
    无限级菜单的实现
  • 原文地址:https://www.cnblogs.com/quyangyang/p/11184215.html
Copyright © 2020-2023  润新知