【Java并发编程】synchronized(一):同步 --生产者消费者问题

在文章的开头先明确几个概念:

  • 并发:多个线程同时操作同一个对象,并要修改其实例变量
    • final 修饰的实例变量线程安全,因为不可变只能初始化一次
  • 锁:OS 的调度无法满足同步的需求,需要程序通过调度算法协助调度
    • synchronized:JVM 级别锁
    • Lock:api 级别
  • synchronized:对象的锁,锁的代码
    • 通过只允许一个线程执行 sync 内代码,保证了可见性,有序性,原子性
  • 并发要求线程交替执行(时间片),而拿了锁会一直将任务执行完再释放(即使n时间片)
    • Java 的线程通信实际是共享内存
  • synchronized 是悲观锁,独占锁,非公平锁,可重入锁
    • 悲观锁 <==> 乐观锁(CAS:注意ABA问题):是否一定要锁
    • 独占锁 <==> 共享锁(读锁、写锁):是否可以有多个线程同时拿锁
    • 非公平锁 <==> 公平锁:是否按阻塞顺序拿锁
    • 可重入锁 <==> 不可重入锁:拿锁线程是否可以多次拿锁

生产者-消费者 demo

要求:

  1. 容器在一个时刻只能做一件事,要么是在被放入产品,要么是在被取出产品
  2. 2 个 Producer,在容器未满时一直生产,如果满了就等待
  3. 10个 Consumer,在容器非空时一直消费,如果为空就等待
public class MyContainer01<T> {
    
    

    // 容器
    LinkedList<T> list = new LinkedList<>();
    // 容器最大容量
    int MAX_SIZE = 10;

    // 保证一个时刻只有一个生产者能生产
    synchronized void put(T t) throws Exception{
    
    
        // while 保证另一个生产者被唤醒后进行二次判断
        while (this.list.size() == MAX_SIZE){
    
    
            // 释放锁,休眠
            this.wait();
        }
        // 生产一个
        this.list.add(t);
        // 模拟生产过程
        TimeUnit.SECONDS.sleep(1); 

        // 唤醒所有 wait 的线程(包括另一个生产者,和所有消费者)
        // 注:这里不用 notify 是因为,只唤醒一个的话,可能唤醒的是另一个生产者
        this.notifyAll();
    }

    // 保证一个时刻只有一个消费者能消费
    synchronized T get() throws Exception{
    
    
        // while 保证唤醒后二次校验
        while (this.list.size() == 0){
    
    
            // 释放锁,休眠
            this.wait();
        }

        // 消费
        T t = list.removeFirst();
        // 模拟消费过程
        TimeUnit.SECONDS.sleep(1); 
        
        // 唤醒所有生产者,消费者
        // 注:这里不用 notify 是因为,只唤醒一个的话,可能是另一个消费者
        this.notifyAll();
        
        return t;
    }

	// main
    public static void main(String[] args) {
    
    
    	// 泛型
        MyContainer01<String> container01 = new MyContainer01<>();
        // 生产计数
        AtomicInteger count = new AtomicInteger(0);

        // 启动 2 个生产者
        for(int i=1;i<=2;i++){
    
    
            new Thread(()->{
    
    
                // 持续生产
                while (true){
    
    
                    try {
    
    
                        container01.put(Thread.currentThread().getName()+ "=>" + count.incrementAndGet());
                    } catch (Exception e) {
    
    
                        e.printStackTrace();
                    }
                    System.out.println("生产-" + Thread.currentThread().getName()+ "=>" + count.get());
                }
            },"scThread"+i).start();
        }

        // 启动 10 个消费者
        for(int i=1;i<=10;i++){
    
    

            new Thread(()-> {
    
    
                try {
    
    
                    while (true) // 持续消费
                        System.out.println("消费-"+Thread.currentThread().getName()+"-"+container01.get());
                } catch (Exception e) {
    
    
                    e.printStackTrace();
                }
            },"xfThread"+i).start();
        }
    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43935927/article/details/114055349