Java Semaphore 生产者消费者线程同步

时间:2022-06-16 21:06:25

一说到Java线程同步,首先想到的就是synchronized关键字,用来锁对象。实际上在Java的java.util.concurrent包中就给我们提供了很多关于同步的工具类。这里为大家介绍Semaphore这个类。这个类是干嘛用的呢?就好比信号标识,它把这十个房间的信息都标识到一个电子信息站牌中,这个信息牌管理所有的房间信息,当有空余的房间时,所有需要放物品的线程都会知道,并抢房间的授权资格,当放抢到授权资格的线程放入物品后,所有需取物品的线程就进入放入物品和抢授权资格的过程。具体代码如下,这个例子,实现了多个线程同时往一个容器中放物品,如果这个容器中的物品数大于10的时候,所有放入线程处于等待状态;还实现了多个线程同时往容器中取物品,当容器中物品为空时,取物线程等待。简单一句话描述:在不冲突的过程中从容器中多放,多取。

package thread.semaphore.two;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class SemaphoreTest {
    public static void main(String[] args) {
        // 线程执行器
        ExecutorService executor = Executors.newCachedThreadPool();
        // 产生仓库
        Warehouse warehouse = new Warehouse();
        // 设置限额信号
        Semaphore notFull = new Semaphore(10);
        // 设置非空信号
        Semaphore notEmpty = new Semaphore(0);
        // 产生生产者
        PutterRunnable putter1 = new PutterRunnable(warehouse, "put1", notFull, notEmpty);
        PutterRunnable putter2 = new PutterRunnable(warehouse, "put2", notFull, notEmpty);
        // 产生消费者
        GetterRunnable getter1 = new GetterRunnable(warehouse, "get1", notFull, notEmpty);
        GetterRunnable getter2 = new GetterRunnable(warehouse, "get2", notFull, notEmpty);

        executor.execute(putter1);
        executor.execute(putter2);
        executor.execute(getter1);
        // 如果有需要,可以把这个方法放开,就可以实现多放多取。
        // executor.execute(getter2);
    }

    // 数据存储仓库
    static class Warehouse {
        // 库存容量
        List<Object> list = new ArrayList<Object>();
        // 核心锁(非冲突锁)
        Semaphore core = new Semaphore(1, true);

        public void put(Object obj, String threadName) {
            try {
                // 保证不冲突
                core.acquire();
                list.add(obj);
                // 判断在生产时,填充位的对象是否是已经有值的,如果有则表示程序错误
                System.out.println("+++ " + threadName + "  list.size = " + list.size() + ";放入的obj=" + obj);
                // 退出核心锁
                core.release();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {

            }
        }

        @SuppressWarnings("finally")
        public Object get(String threadName) {

            Object obj = null;
            try {
                // 保证不冲突
                core.acquire();
                obj = list.remove(0);
                // 判断在消费时,需要消费位置的对象是否是空的。,如果有则表示程序错误
                System.out.println("            --- " + threadName + "  list.size = " + list.size() + ";取出的obj=" + obj);
                // 退出核心锁
                core.release();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                return obj;
            }

        }
    }

    // putter线程,
    static class PutterRunnable implements Runnable {
        Warehouse warehouse;
        Random random;
        String rannableName;
        // 非满锁
        Semaphore notFull;
        // 非空锁
        Semaphore notEmpty;

        public PutterRunnable(Warehouse warehouse, String rannableName, Semaphore notFull, Semaphore notEmpty) {
            this.warehouse = warehouse;
            random = new Random();
            this.rannableName = rannableName;
            this.notFull = notFull;
            this.notEmpty = notEmpty;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    // 获取存储限额的插入许可,如果达到限额,则等待插入许可,否则继续往下执行
                    notFull.acquire();
                    warehouse.put((Object) (random.nextInt() + ""), rannableName);
                    // 插入成功后,则添加非空的授权许可。以供获取线程获取
                    notEmpty.release();
                    // TimeUnit.SECONDS.sleep(1);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    static class GetterRunnable implements Runnable {
        Warehouse warehouse;
        String rannableName;
        // 非空锁,当是0的时候进行阻塞
        Semaphore notEmpty;
        // 非满锁
        Semaphore notFull;

        public GetterRunnable(Warehouse warehouse, String rannableName, Semaphore notFull, Semaphore notEmpty) {
            this.warehouse = warehouse;
            this.rannableName = rannableName;
            this.notFull = notFull;
            this.notEmpty = notEmpty;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    // 获取非空授权许可,如果为空,则一直阻塞,等待插入线程插入后添加非空许可
                    notEmpty.acquire();
                    warehouse.get(rannableName);
                    // 添加存储限额的插入许可,表示插入线程可以进行添加操作了
                    notFull.release();
                    TimeUnit.SECONDS.sleep(1);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

        }
    }
}

执行结果如下:

<div>
+++ put1 list.size = 1;放入的obj=-2139723420
+++ put2 list.size = 2;放入的obj=-1572405971
+++ put1 list.size = 3;放入的obj=-1705274050
--- get1 list.size = 2;取出的obj=-2139723420
+++ put2 list.size = 3;放入的obj=734422456
+++ put1 list.size = 4;放入的obj=-1619127788
+++ put2 list.size = 5;放入的obj=-1719033923
+++ put1 list.size = 6;放入的obj=-122350698
+++ put2 list.size = 7;放入的obj=2035853367
+++ put1 list.size = 8;放入的obj=-538022868
+++ put2 list.size = 9;放入的obj=-1842381319
+++ put1 list.size = 10;放入的obj=-1810284972
--- get1 list.size = 9;取出的obj=-1572405971
+++ put2 list.size = 10;放入的obj=-555471275
--- get1 list.size = 9;取出的obj=-1705274050
+++ put1 list.size = 10;放入的obj=-1173490502
--- get1 list.size = 9;取出的obj=734422456
+++ put2 list.size = 10;放入的obj=-313790792
--- get1 list.size = 9;取出的obj=-1619127788
+++ put1 list.size = 10;放入的obj=-1067498081
--- get1 list.size = 9;取出的obj=-1719033923
+++ put2 list.size = 10;放入的obj=-1634780208
--- get1 list.size = 9;取出的obj=-122350698
+++ put1 list.size = 10;放入的obj=-1420550696
--- get1 list.size = 9;取出的obj=2035853367
+++ put2 list.size = 10;放入的obj=2036388541
--- get1 list.size = 9;取出的obj=-538022868
+++ put1 list.size = 10;放入的obj=-320507030
--- get1 list.size = 9;取出的obj=-1842381319
+++ put2 list.size = 10;放入的obj=1682783427
--- get1 list.size = 9;取出的obj=-1810284972
+++ put1 list.size = 10;放入的obj=243200254

<div>