并发编程基础五(线程相关方法1)

shell 复制代码
#回顾
1.在java编程语言中,与线程相关的方法主要有:
 1.1.Object.wait/Object.notify/Object/notifyAll
 1.2.Thread.sleep/Thread.join/Thread.yield
2.需要把各个方法的作用和使用场景说清楚,需要用两篇文章进行分享

#考考你
1.你知道wait/notify/notifyAll方法的作用吗?
2.你知道notify与notifyAll方法的区别吗?
3.你知道sleep方法的作用吗?
4.你知道wait与sleep方法的区别吗?
5.你知道join方法的作用吗?
6.你知道yield方法的作用吗?

案例:wait/notify/notifyAll

方法简述:

wait:释放线程拥有的当前锁对象,让线程进入WAITING状态

notify:唤醒当前锁对象等待池(WaitSet)中,某一个线程

notifyAll:唤醒当前锁对象等待池(WaitSet)中,所有线程

业务描述:

1.通过wait与notify(notifyAll)实现线程协同,实现经典的生产者消费者模式

2.编写生产者,向队列中生产数据,如果队列满,生产者进行等待,并唤醒消费者进行消费

3.编写消费者,从队列中消费数据,如果队列空,消费者进行等待,并唤醒生产者进行生产

4.在主类main方法中,创建两个生产者线程进行生产

5.在主类main方法中,创建一个消费者线程进行消费

生产者:

java 复制代码
/**
 * 生产者
 */
class Producer implements Runnable{

    public void run() {
        while(true){
            synchronized (ProducerConsumerDemo.LOCK){
                // 检查队列是否满,推荐用while而不是if
                while(ProducerConsumerDemo.QUEUE.size() ==
                        ProducerConsumerDemo.CAPACITY){
                    // 如果队列满,则等待消费者消费
                    try {
                        System.out.println("队列满size:" +ProducerConsumerDemo.QUEUE.size()+ ",线程【" +
                                Thread.currentThread().getName() + "】正在等待消费者消费.");
                        ProducerConsumerDemo.LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                // 如果队列不满,则正常生产
                ProducerConsumerDemo.QUEUE.add(1);
                System.out.println("线程【" + Thread.currentThread().getName() +
                        "】生产了数据.当前队列size:" + ProducerConsumerDemo.QUEUE.size());

                // 唤醒消费者
                ProducerConsumerDemo.LOCK.notifyAll();
            }
        }
    }
}

消费者:

java 复制代码
/**
 * 消费者
 */
class Consumer implements Runnable{

    public void run() {
        while(true){
            synchronized (ProducerConsumerDemo.LOCK){
                // 检查队列是否空,推荐用while而不是if
                while(ProducerConsumerDemo.QUEUE.isEmpty()){
                    // 如果队列空,则等待生产者生产
                    try {
                        System.out.println("队列空size:" +ProducerConsumerDemo.QUEUE.size()+ ",线程【" +
                                Thread.currentThread().getName() + "】正在等待生产者生产.");
                        ProducerConsumerDemo.LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                // 如果队列不空,则正常消费
                ProducerConsumerDemo.QUEUE.remove(0);
                System.out.println("线程【" + Thread.currentThread().getName() +
                        "】消费了数据.当前队列size:" + ProducerConsumerDemo.QUEUE.size());

                // 唤醒生产者
                ProducerConsumerDemo.LOCK.notifyAll();
            }
        }
    }
}

完整代码:

java 复制代码
package com.anan.thread.threadmethod;

import java.util.ArrayList;

/**
 * 生产者消费者模型:wait与notify(notifyAll)
 */
public class ProducerConsumerDemo {

    // 定义公共资源:队列容量、队列
    public final static Integer CAPACITY = 6;
    public final static ArrayList<Integer> QUEUE = new ArrayList<Integer>(CAPACITY);

    // 定义锁对象
    public final static Object LOCK = new Object();

    public static void main(String[] args) {

        // 创建两个生产者线程
        Runnable r1 = new Producer();
        Thread producer0 = new Thread(r1,"producer-0");
        producer0.start();

        Thread producer1 = new Thread(r1,"producer-1");
        producer1.start();

        // 创建消费者线程
        Runnable r2 = new Consumer();
        Thread consumer1 = new Thread(r2,"consumer-0");
        consumer1.start();

    }
}

/**
 * 生产者
 */
class Producer implements Runnable{

    public void run() {
        while(true){
            synchronized (ProducerConsumerDemo.LOCK){
                // 检查队列是否满,推荐用while而不是if
                while(ProducerConsumerDemo.QUEUE.size() ==
                        ProducerConsumerDemo.CAPACITY){
                    // 如果队列满,则等待消费者消费
                    try {
                        System.out.println("队列满size:" +ProducerConsumerDemo.QUEUE.size()+ ",线程【" +
                                Thread.currentThread().getName() + "】正在等待消费者消费.");
                        ProducerConsumerDemo.LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                // 如果队列不满,则正常生产
                ProducerConsumerDemo.QUEUE.add(1);
                System.out.println("线程【" + Thread.currentThread().getName() +
                        "】生产了数据.当前队列size:" + ProducerConsumerDemo.QUEUE.size());

                // 唤醒消费者
                ProducerConsumerDemo.LOCK.notifyAll();
            }
        }
    }
}

/**
 * 消费者
 */
class Consumer implements Runnable{

    public void run() {
        while(true){
            synchronized (ProducerConsumerDemo.LOCK){
                // 检查队列是否空,推荐用while而不是if
                while(ProducerConsumerDemo.QUEUE.isEmpty()){
                    // 如果队列空,则等待生产者生产
                    try {
                        System.out.println("队列空size:" +ProducerConsumerDemo.QUEUE.size()+ ",线程【" +
                                Thread.currentThread().getName() + "】正在等待生产者生产.");
                        ProducerConsumerDemo.LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                // 如果队列不空,则正常消费
                ProducerConsumerDemo.QUEUE.remove(0);
                System.out.println("线程【" + Thread.currentThread().getName() +
                        "】消费了数据.当前队列size:" + ProducerConsumerDemo.QUEUE.size());

                // 唤醒生产者
                ProducerConsumerDemo.LOCK.notifyAll();
            }
        }
    }
}

总结

shell 复制代码
#考考你答案
1.你知道wait/notify/notifyAll方法的作用吗?
 1.1.wait/notify/notifyAll都是Object中的方法
 1.2.通过等待与唤醒,实现线程之间的协同
 1.3.wait方法会释放当前锁对象,让线程进入WAITING状态
 1.4.notify方法用于:
  1.4.1.唤醒当前锁对象等待池(WaitSet)中,正在等待
   当前锁对象的某一个线程
  1.4.2.让该线程进入RUNNABLE状态,并移入锁池(EntrySet)中,
  重新竞争锁对象
 1.5.notifyAll方法用于:
  1.5.1.唤醒当前锁对象等待池(WaitSet)中,正在等待
   当前锁对象的所有线程
  1.5.2.让等待当前锁对象的所有线程,进入RUNNABLE状态,并
   移入锁池(EntrySet)中,重新竞争锁对象
  
2.你知道notify与notifyAll方法的区别吗?
 2.1.通过以上1.4点、1.5点已经说明了notify
 与notifyAll的区别
 2.2.这里可能有朋友不明白锁池(EntrySet),与
 等待池(WaitSet)的概念。我们通过一个图进行说明:
  
#流程文字描述:
1.锁池(EntrySet):代表正在等待同一锁对象的线程集合,线程进入BLOCKED状态
2.拥有者(Owner):代表已经获取到锁对象的线程
3.等待池(WaitSet):代表已经进入WAITING状态,等待被唤醒的线程集合
4.流程描述:
  4.1.enter:线程准备获取锁对象,此时锁被其它线程占有,线程进入EntrySet
  4.2.acquire:当其它线程释放锁对象,EntrySet中的某个线程获取占有锁对象
  4.3.release:占有锁对象线程,通过wait方式释放锁对象,进入WaitSet中,等待被唤醒
  4.4.acquire:当有其它线程,通过notify/notifyAll方法唤醒WaitSet中线程,线程将重新进入EntrySet,重新竞争获取锁对象
  4.5.release and exit:占有锁对象线程,释放锁并退出执行,线程生命周期结束 
相关推荐
oscar9999 分钟前
Maven项目中不修改 pom.xml 状况下直接运行OpenRewrite的配方
java·maven·openrewrite
南宫生9 分钟前
力扣-数据结构-3【算法学习day.74】
java·数据结构·学习·算法·leetcode
工业甲酰苯胺15 分钟前
聊一聊 C#线程池 的线程动态注入
java·开发语言·c#
m0_7482402522 分钟前
docker--压缩镜像和加载镜像
java·docker·eureka
向宇it26 分钟前
【从零开始入门unity游戏开发之——C#篇30】C#常用泛型数据结构类——list<T>列表、`List<T>` 和数组 (`T[]`) 的选择
java·开发语言·数据结构·unity·c#·游戏引擎·list
葡萄架子26 分钟前
Python中的logger作用(from loguru import logger)
java·前端·python
daopuyun40 分钟前
GB/T34944-2017 《Java语言源代码漏洞测试规范》解读——安全功能
java·开发语言·安全
编程洪同学44 分钟前
Spring Boot 中实现自定义注解记录接口日志功能
android·java·spring boot·后端
小小药1 小时前
009-spring-bean的实例化流程
java·数据库·spring
罗政1 小时前
PDF书籍《手写调用链监控APM系统-Java版》第12章 结束
java·开发语言·pdf