0
点赞
收藏
分享

微信扫一扫

Semaphore 信号量

大自然在召唤 2022-03-14 阅读 42

java.util.concurrent简称JUC

Semaphore 信号量

Semaphore 信号量 英[ˈseməfɔː®],Semaphore可以控制同时访问的线程个数,通过acquire()方法获取一个许可,如果没有就等待,通过release()可以释放一个许可。

构造方法
    /**
     * 使用指定数量许可和非公平规则创建一个信号量
     *
     * @param permits 指定信号量的数量
     */
    public Semaphore(int permits) {
        sync = new Nonfai
    }
	/**
     * 使用指定数量许可和指定公平规则创建一个信号量
     *
     * @param permits 指定信号量的数量
     * @param fair 是否是公平的,即等待时间越久的越先获取许可
     */
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }
常用方法
	/**
     * 尝试获取一个许可,如果获取成功,则立即返回true。如果获取失败,则立即返回false。如果没有许可可以获得,则会一直等待,直到获得许可。
     */
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
    /**
     * 尝试获取permits个许可,如果获取成功,则立即返回true。如果获取失败,则立即返回false。如果没有许可可以获得,则会一直等待,直到获得许可。
     * @param permits 信号量的数量
     */
    public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireSharedInterruptibly(permits);
    }
	/**
     * 释放1个许可证,并发回给信号机。将可用许可证数量增加1。
     */
    public void release() {
        sync.releaseShared(1);
    }
    /**
     * 尝试获取一个许可,若获取成功,则立即返回true,若获取失败,则立即返回false
     */
    public boolean tryAcquire(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.nonfairTryAcquireShared(permits) >= 0;
    }
	/**
     * 尝试获取一个许可,若在指定的时间内获取成功,则立即返回true,否则则立即返回false
     */
    public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
        throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
    }
	/**
     * 尝试获取permits个许可,若获取成功,则立即返回true,若获取失败,则立即返回false
     */
    public boolean tryAcquire(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.nonfairTryAcquireShared(permits) >= 0;
    }
/**
     * 尝试获取permits个许可,若在指定的时间内获取成功,则立即返回true,否则则立即返回false
     */
    public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
        throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
    }
	/**
     * 返回此信号量中当前可用的许可证数。
     * @return 可用的许可数目
     */
    public int availablePermits() {
        return sync.getPermits();
    }
举一个简单的例子

通过Semaphore信号量来实现。我们的工厂一共就有5台机器可以同时生产材料。一台机器同时只能被1个工人使用,只有这个工人使用完了,其他工人才能继续使用。

package com.test.juc;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Semaphore;

/**
 * @author liao
 * @version 1.0.0
 * @description
 * @date 2022/3/10 14:33
 **/
@Slf4j
public class TestSemaphore {
    public static void main(String[] args) {
        int N = 8;            //工人数
        Semaphore semaphore = new Semaphore(5); //机器数目
        for (int i = 0; i < N; i++) {
            new Worker(i, semaphore).start();
        }
        log.info("END");
    }

    static class Worker extends Thread {
        private int num;
        private Semaphore semaphore;

        public Worker(int num, Semaphore semaphore) {
            this.num = num;
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            try {
                semaphore.acquire();
                log.info("工人" + this.num + "占用一个机器在生产...");
                Thread.sleep(2000);
                log.info("工人" + this.num + "释放出机器");
                semaphore.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
执行结果
14:14:15.240 [Thread-4] INFO com.test.juc.TestSemaphore - 工人4占用一个机器在生产...
14:14:15.239 [Thread-1] INFO com.test.juc.TestSemaphore - 工人1占用一个机器在生产...
14:14:15.239 [Thread-3] INFO com.test.juc.TestSemaphore - 工人3占用一个机器在生产...
14:14:15.240 [Thread-2] INFO com.test.juc.TestSemaphore - 工人2占用一个机器在生产...
14:14:15.240 [main] INFO com.test.juc.TestSemaphore - END
14:14:15.240 [Thread-0] INFO com.test.juc.TestSemaphore - 工人0占用一个机器在生产...
14:14:17.257 [Thread-4] INFO com.test.juc.TestSemaphore - 工人4释放出机器
14:14:17.257 [Thread-1] INFO com.test.juc.TestSemaphore - 工人1释放出机器
14:14:17.257 [Thread-0] INFO com.test.juc.TestSemaphore - 工人0释放出机器
14:14:17.257 [Thread-5] INFO com.test.juc.TestSemaphore - 工人5占用一个机器在生产...
14:14:17.257 [Thread-2] INFO com.test.juc.TestSemaphore - 工人2释放出机器
14:14:17.257 [Thread-6] INFO com.test.juc.TestSemaphore - 工人6占用一个机器在生产...
14:14:17.257 [Thread-3] INFO com.test.juc.TestSemaphore - 工人3释放出机器
14:14:17.258 [Thread-7] INFO com.test.juc.TestSemaphore - 工人7占用一个机器在生产...
14:14:19.264 [Thread-7] INFO com.test.juc.TestSemaphore - 工人7释放出机器
14:14:19.264 [Thread-6] INFO com.test.juc.TestSemaphore - 工人6释放出机器
14:14:19.264 [Thread-5] INFO com.test.juc.TestSemaphore - 工人5释放出机器
实战
工具类
package com.test.juc;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * 线程信号量
 *
 * @author tengbx
 */
public class ThreadSemaphoreUtil {
    private final static Logger LOGGER = LoggerFactory.getLogger(ThreadSemaphoreUtil.class);

    /**
     * 线程执行信号量
     */
//	public static final int THREAD_SEMAPHORE= Integer.parseInt(PropertyUtil.getProperty("THREAD_SEMAPHORE", "/config/properties/system.properties"));
    public static final int THREAD_SEMAPHORE = 3;
    //信号量
    static Semaphore SEMAPHORE = new Semaphore(THREAD_SEMAPHORE, true);
    //线程池
    static ExecutorService pool = Executors.newCachedThreadPool();
    static long start = System.currentTimeMillis();

    //重新执行
    public static void restart() {
        SEMAPHORE = new Semaphore(THREAD_SEMAPHORE, true);
        pool = Executors.newCachedThreadPool();
        start = System.currentTimeMillis();
    }

    //执行线程
    public static void execute(Runnable runnable) throws InterruptedException {
        pool.execute(runnable);
    }

    //等待全部线程池任务执行完成
    public static void allDone() throws InterruptedException {
        pool.shutdown();
        int i = 0;
        while (true) {
            LOGGER.info("allDone当前系统的并发数是:" + (THREAD_SEMAPHORE - SEMAPHORE.availablePermits()));
            // 线程池关闭后所有任务执行完成 && 设置线程数-信号量中的可用的令牌数量==0
            if (pool.isTerminated() && THREAD_SEMAPHORE - SEMAPHORE.availablePermits() == 0) {
                LOGGER.info("allDone所有的子线程都结束了");
                break;
            }
            if (++i > 60) {
                Thread.sleep(6000);
            } else if (++i > 30) {
                Thread.sleep(3000);
            } else {
                Thread.sleep(1000);
            }
        }
    }

    public static void acquire() throws InterruptedException {
        SEMAPHORE.acquire();//获取信号灯许可
        LOGGER.info("获取信号灯许可");
    }

    public static void release() {
        SEMAPHORE.release();//释放信号灯
        LOGGER.info("释放信号灯");
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            final int j = i;
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        ThreadSemaphoreUtil.acquire();//获取信号灯许可
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    try {
                        Thread.sleep(new Random().nextInt(10000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ThreadSemaphoreUtil.release();//释放信号灯
                }
            };
            ThreadSemaphoreUtil.execute(runnable);
        }
        ThreadSemaphoreUtil.allDone();
    }
}
执行结果
14:28:35.300 [pool-1-thread-4] INFO com.test.juc.ThreadSemaphoreUtil - 获取信号灯许可
14:28:35.301 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:3
14:28:35.300 [pool-1-thread-1] INFO com.test.juc.ThreadSemaphoreUtil - 获取信号灯许可
14:28:35.301 [pool-1-thread-3] INFO com.test.juc.ThreadSemaphoreUtil - 获取信号灯许可
14:28:35.947 [pool-1-thread-3] INFO com.test.juc.ThreadSemaphoreUtil - 释放信号灯
14:28:35.947 [pool-1-thread-2] INFO com.test.juc.ThreadSemaphoreUtil - 获取信号灯许可
14:28:36.316 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:3
14:28:36.603 [pool-1-thread-5] INFO com.test.juc.ThreadSemaphoreUtil - 获取信号灯许可
14:28:36.603 [pool-1-thread-2] INFO com.test.juc.ThreadSemaphoreUtil - 释放信号灯
14:28:37.317 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:3
14:28:38.317 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:3
14:28:38.989 [pool-1-thread-5] INFO com.test.juc.ThreadSemaphoreUtil - 释放信号灯
14:28:38.989 [pool-1-thread-6] INFO com.test.juc.ThreadSemaphoreUtil - 获取信号灯许可
14:28:39.317 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:3
14:28:40.317 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:3
14:28:40.578 [pool-1-thread-9] INFO com.test.juc.ThreadSemaphoreUtil - 获取信号灯许可
14:28:40.578 [pool-1-thread-1] INFO com.test.juc.ThreadSemaphoreUtil - 释放信号灯
14:28:41.318 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:3
14:28:42.318 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:3
14:28:43.012 [pool-1-thread-6] INFO com.test.juc.ThreadSemaphoreUtil - 释放信号灯
14:28:43.012 [pool-1-thread-10] INFO com.test.juc.ThreadSemaphoreUtil - 获取信号灯许可
14:28:43.158 [pool-1-thread-9] INFO com.test.juc.ThreadSemaphoreUtil - 释放信号灯
14:28:43.158 [pool-1-thread-7] INFO com.test.juc.ThreadSemaphoreUtil - 获取信号灯许可
14:28:43.319 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:3
14:28:43.598 [pool-1-thread-4] INFO com.test.juc.ThreadSemaphoreUtil - 释放信号灯
14:28:43.598 [pool-1-thread-8] INFO com.test.juc.ThreadSemaphoreUtil - 获取信号灯许可
14:28:44.319 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:3
14:28:45.304 [pool-1-thread-7] INFO com.test.juc.ThreadSemaphoreUtil - 释放信号灯
14:28:45.321 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:2
14:28:46.321 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:2
14:28:47.321 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:2
14:28:48.322 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:2
14:28:48.857 [pool-1-thread-8] INFO com.test.juc.ThreadSemaphoreUtil - 释放信号灯
14:28:49.323 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:1
14:28:50.323 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:1
14:28:50.855 [pool-1-thread-10] INFO com.test.juc.ThreadSemaphoreUtil - 释放信号灯
14:28:53.323 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone当前系统的并发数是:0
14:28:53.323 [main] INFO com.test.juc.ThreadSemaphoreUtil - allDone所有的子线程都结束了
举报

相关推荐

0 条评论