16. 线程通信-传统方式

java 多线程系列文章列表, 请查看目录: 《java 多线程学习笔记》

1. 线程通信的传统方式

传统的线程通信方式指的是借助于, Object 基类中的wait(), notify(), notifyAll()方法. 这三个方法必须由同步监视器对象进行调用, 影响的也只是同一同步监视器的相关线程.

1.1 同步监视器

同步监视器, 也就是指监视的资源. 对于synchronized 同步方式, 有两种情况:

  • synchronized 修饰的同步方法, 同步监视器为该对象实例 this
  • synchronized 修饰的同步代码块儿, 同步监视器为括号里的对象, 因此必须调用该括号内的对象的wait(), notify(), notifyAll() 方法
// 同步方法, 默认同步监视器为this对象, 所以直接调用this 对象的wait(), notify(), notifyAll() 方法
synchronized public void doWait(){
    try {
        this.wait();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

// 同步代码块儿, 同步监视器为字符串常量"hello", 所以需要使用字符串的wait()方法. 
// 需要注意的是, 由于java 常量位于常量池中, 所以相同字符串为同一对象, 所以可不指定变量名称.
public void doWait(){
    synchronized ("hello"){
        try {
            "hello".wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

1.2 API 说明

  • wait(): 阻塞API, 使线程由运行状态转为阻塞状态, 等待被唤醒.
  • notify(): 唤醒当前同步监视器的任一一个等待线程, 使线程由阻塞状态转为就绪状态, 等待cpu 资源调度
  • notifyAll(): 唤醒当前同步监视器的所有等待线程.

2. 线程通信测试

笔者来模拟一个生产者消费者模型, 当

2.1 Product

  • 笔者采用同步方法方式, 因此默认同步监视器为 this
  • 当产品数量小于0时, 销售等待, 当产品大于0 时, 可以销售.
public class Product {

    private int number = 1;

    synchronized public void sale(){
        try {

            // 如果商品数量小于0 , 则线程等待
            while (number <= 0) {
                System.out.println("商品剩余为0, 等待补货!");
                this.wait();
            }

            System.out.println(Thread.currentThread().getName() + "-售出1件商品, 剩余商品:" + --number);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    synchronized public void purchase() {

        try {

            System.out.println(Thread.currentThread().getName() + "-进货1件商品, 剩余商品:" + ++number);

            // 通知所有的等待线程, 可能会产生虚假唤醒
            this.notifyAll();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.2 测试类

笔者启动3个消费者线程, 1个生产者线程. 这样便有3个消费者线程在等待.

public static void main(String[] args) {

    Product product = new Product();

    // 启动三个线程消费
    for (int i = 0; i < 3; i++) {
        new Thread("消费者" + i){
            @Override
            public void run() {
                while (true) {
                    product.sale();
                    ThreadUtil.sleep(5);
                }
            }
        }.start();
    }

    // 启动一个线程生产
    new Thread("生产者"){
        @Override
        public void run() {
            while (true) {
                product.purchase();
                ThreadUtil.sleep(10);
            }
        }
    }.start();

    ThreadUtil.sleep(10000);
}

2.3 测试输出

从测试可看出, 当商品剩余数量为0时, 消费者线程进行等待.

消费者0-售出1件商品, 剩余商品:0
生产者-进货1件商品, 剩余商品:1
消费者2-售出1件商品, 剩余商品:0
商品剩余为0, 等待补货!
商品剩余为0, 等待补货!
商品剩余为0, 等待补货!
生产者-进货1件商品, 剩余商品:1
消费者1-售出1件商品, 剩余商品:0
商品剩余为0, 等待补货!
商品剩余为0, 等待补货!
商品剩余为0, 等待补货!
生产者-进货1件商品, 剩余商品:1
消费者0-售出1件商品, 剩余商品:0
发布了321 篇原创文章 · 获赞 676 · 访问量 147万+

猜你喜欢

转载自blog.csdn.net/zongf0504/article/details/100186190