JUC:4_1并发协作模型:生产者消费者模型

JUC:4_1并发协作模型:生产者消费者模型

  • 线程通信问题
  • synchronized版本的管程法
  • Lock版本的管程法

线程通信问题

线程之间的通信问题,就是生产者和消费者问题,也就是如何做到多个线程交替执行。

并发协作模型:生产者消费者模型 解决方式1.管程法
并发协作模型:生产者消费者模型 解决方式2.信号灯法

上面两个是基于synchronized、wait、notify来去做的,现在改为Lock去做。

synchronized版本的管程法

/**
 * 并发协作模型"生产者/消费者模式"
 * 线程之间的通信问题,就是生产者和消费者问题,也就是如何做到多个线程交替执行
 * 比如一个线程++A
 * 一个线程--A
 * 需要先放入再执行另一个操作
 */
public class TestPC {

    public static void main(String[] args) {

        SyncContainer container = new SyncContainer();
        //生产者
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                container.push(new Product(i));
                System.out.println("将产品放入缓冲区:" + i);
            }
        }).start();

        //消费者
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                System.out.println("消费产品" + container.pop().getPid());
            }
        }).start();
    }
}

//产品
class Product {

    private int pid;//产品编号

    public int getPid() {
        return pid;
    }

    public void setPid(int pid) {
        this.pid = pid;
    }

    public Product(int pid) {
        this.pid = pid;
    }
}

//缓冲区
class SyncContainer {

    //容器大小,默认容量指定10
    private static final int DEFAULT_CAPACITY = 10;
    Product[] products = new Product[DEFAULT_CAPACITY];

    //容器计数器
    int count = 0;

    //生产者放产品
    public synchronized void push(Product product) {

        if (count == products.length) {
            //容器已满,需要等待消费
            //通知消费者消费,生产者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //容器不满,可以放产品
        products[count] = product;
        count++;
        //通知消费者消费,这里用notifyAll和notify结果都是一样的,因为不会同时阻塞
        this.notifyAll();
    }

    //消费者消费产品
    public synchronized Product pop() {

        //判断容器有无产品,无则阻塞
        if (count == 0) {
            //等待生产者生产,消费者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //可以消费,这里主要:count--必须在前,因为生产者生产之后count++会+1
        count--;
        Product product = products[count];
        //通知生产者生产,这里用notifyAll和notify结果都是一样的,因为不会同时阻塞
        this.notify();
        return product;
    }
}

输出:

将产品放入缓冲区:0
将产品放入缓冲区:1
将产品放入缓冲区:2
将产品放入缓冲区:3
将产品放入缓冲区:4
将产品放入缓冲区:5
将产品放入缓冲区:6
将产品放入缓冲区:7
将产品放入缓冲区:8
将产品放入缓冲区:9
消费产品9
将产品放入缓冲区:10
消费产品10
将产品放入缓冲区:11
将产品放入缓冲区:12
消费产品11
消费产品12
将产品放入缓冲区:13
消费产品13
将产品放入缓冲区:14
消费产品14
将产品放入缓冲区:15
消费产品15
将产品放入缓冲区:16
将产品放入缓冲区:17
消费产品16
消费产品17
将产品放入缓冲区:18
将产品放入缓冲区:19
消费产品18
消费产品19
将产品放入缓冲区:20
将产品放入缓冲区:21
消费产品20
消费产品21
将产品放入缓冲区:22
消费产品22
将产品放入缓冲区:23
消费产品23
消费产品24
将产品放入缓冲区:24
消费产品8
将产品放入缓冲区:25
消费产品25
将产品放入缓冲区:26
消费产品26
将产品放入缓冲区:27
将产品放入缓冲区:28
消费产品27
将产品放入缓冲区:29
消费产品29
将产品放入缓冲区:30
消费产品30
将产品放入缓冲区:31
消费产品31
将产品放入缓冲区:32
消费产品32
将产品放入缓冲区:33
消费产品33
将产品放入缓冲区:34
消费产品34
将产品放入缓冲区:35
消费产品35
将产品放入缓冲区:36
消费产品36
将产品放入缓冲区:37
消费产品37
将产品放入缓冲区:38
消费产品38
将产品放入缓冲区:39
消费产品39
将产品放入缓冲区:40
消费产品40
将产品放入缓冲区:41
消费产品41
将产品放入缓冲区:42
消费产品42
将产品放入缓冲区:43
消费产品43
将产品放入缓冲区:44
消费产品44
将产品放入缓冲区:45
消费产品45
将产品放入缓冲区:46
消费产品46
将产品放入缓冲区:47
消费产品47
将产品放入缓冲区:48
消费产品48
将产品放入缓冲区:49
消费产品49
将产品放入缓冲区:50
消费产品50
将产品放入缓冲区:51
消费产品51
将产品放入缓冲区:52
消费产品52
将产品放入缓冲区:53
消费产品53
将产品放入缓冲区:54
消费产品54
将产品放入缓冲区:55
消费产品55
将产品放入缓冲区:56
消费产品56
将产品放入缓冲区:57
消费产品57
将产品放入缓冲区:58
消费产品58
将产品放入缓冲区:59
消费产品59
将产品放入缓冲区:60
消费产品60
将产品放入缓冲区:61
消费产品61
将产品放入缓冲区:62
消费产品62
将产品放入缓冲区:63
将产品放入缓冲区:64
消费产品63
消费产品64
消费产品65
将产品放入缓冲区:65
消费产品28
将产品放入缓冲区:66
消费产品66
将产品放入缓冲区:67
消费产品67
将产品放入缓冲区:68
消费产品68
将产品放入缓冲区:69
消费产品69
将产品放入缓冲区:70
消费产品70
将产品放入缓冲区:71
消费产品71
将产品放入缓冲区:72
消费产品72
将产品放入缓冲区:73
消费产品73
将产品放入缓冲区:74
消费产品74
将产品放入缓冲区:75
将产品放入缓冲区:76
消费产品75
将产品放入缓冲区:77
消费产品77
将产品放入缓冲区:78
将产品放入缓冲区:79
消费产品78
消费产品79
将产品放入缓冲区:80
将产品放入缓冲区:81
消费产品80
消费产品81
将产品放入缓冲区:82
消费产品82
将产品放入缓冲区:83
消费产品83
将产品放入缓冲区:84
消费产品84
将产品放入缓冲区:85
将产品放入缓冲区:86
消费产品85
消费产品86
将产品放入缓冲区:87
消费产品87
将产品放入缓冲区:88
消费产品88
将产品放入缓冲区:89
消费产品89
消费产品90
将产品放入缓冲区:90
消费产品76
将产品放入缓冲区:91
消费产品91
将产品放入缓冲区:92
消费产品92
将产品放入缓冲区:93
消费产品93
将产品放入缓冲区:94
消费产品94
将产品放入缓冲区:95
消费产品95
将产品放入缓冲区:96
消费产品96
将产品放入缓冲区:97
消费产品97
将产品放入缓冲区:98
消费产品98
将产品放入缓冲区:99
消费产品99
消费产品7
消费产品6
消费产品5
消费产品4
消费产品3
消费产品2
消费产品1
消费产品0

Lock版本的管程法

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 并发协作模型"生产者/消费者模式"
 * 线程之间的通信问题,就是生产者和消费者问题,也就是如何做到多个线程交替执行
 * 比如一个线程++A
 * 一个线程--A
 * 需要先放入再执行另一个操作
 */
public class TestPC2 {

    public static void main(String[] args) {

        SyncContainer container = new SyncContainer();
        //生产者
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                container.push(new Product(i));
                System.out.println("将产品放入缓冲区:" + i);
            }
        }).start();

        //消费者
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                System.out.println("消费产品:" + container.pop().getPid());
            }
        }).start();
    }
}

//产品
class Product2 {

    private int pid;//产品编号

    public int getPid() {
        return pid;
    }

    public void setPid(int pid) {
        this.pid = pid;
    }

    public Product2(int pid) {
        this.pid = pid;
    }
}

//缓冲区
class SyncContainer2 {

    //容器大小,默认容量指定10
    private static final int DEFAULT_CAPACITY = 10;
    Product2[] products = new Product2[DEFAULT_CAPACITY];
    final Lock lock = new ReentrantLock();//默认非公平锁,可以添加true类型设置为公平锁
    final Condition productor = lock.newCondition();
    final Condition consumer = lock.newCondition();


    //容器计数器
    int count = 0;

    //生产者放产品
    public void push(Product2 product) {

        lock.lock();//加锁
        //lock.tryLock();//尝试获取锁,这个就是和synchronized区别,不会傻傻的一直等待
        try {
            if (count > products.length) {//
                //容器已满,需要等待消费
                //通知消费者消费,生产者等待
                try {
                    productor.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //容器不满,可以放产品
            products[count] = product;
            count++;
            //通知消费者消费,这里与sychonized的唤醒时用的notifyAll和notify不同,用signal
            consumer.signal();
        } finally {
            lock.unlock();//解锁
        }
    }

    //消费者消费产品
    public Product2 pop() {

        lock.lock();//加锁
        Product2 product;
        try {
            //lock.tryLock();//尝试获取锁,这个就是和synchronized区别,不会傻傻的一直等待
            //判断容器有无产品,无则阻塞
            if (count == 0) {
                //等待生产者生产,消费者等待
                try {
                    consumer.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //可以消费,这里主要:count--必须在前,因为生产者生产之后count++会+1
            count--;
            product = products[count];
            productor.signal();
        } finally {
            lock.unlock();
        }
        return product;
    }
}

你可能感兴趣的:(java,后端,多线程)