天天看點

用Semaphore信号量控制線程執行

作者:頑石九變

Semaphore重點文法

  • availablePermits():判斷是否有權限
  • acquire():獲得一個信号,阻塞線程,可被中斷
  • release():釋放一個信号
  • acquireUninterruptibly():獲得一個信号,阻塞線程,不可被中斷

代碼示例

每次隻允許2個線程執行

public class SemaphoreThread {

    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(2);
        // 建立一個緩存線程池
        ExecutorService es = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            es.submit(new Thread(() -> {
                String name = Thread.currentThread().getName();
                try {
                    semaphore.acquire();
                    System.out.println(LocalDateTime.now().toLocalTime()+"  "+name + "開始執行");
                    Thread.sleep(1000);
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }));
        }
        // 關閉線程池
        es.shutdown();
    }
}
           

輸出:

13:42:11.763  pool-1-thread-2開始執行
13:42:11.763  pool-1-thread-1開始執行
13:42:12.764  pool-1-thread-3開始執行
13:42:12.764  pool-1-thread-5開始執行
13:42:13.764  pool-1-thread-6開始執行
13:42:13.764  pool-1-thread-4開始執行
13:42:14.764  pool-1-thread-9開始執行
13:42:14.764  pool-1-thread-10開始執行
13:42:15.765  pool-1-thread-7開始執行
13:42:15.765  pool-1-thread-8開始執行
           
從輸出日志可以看出,每秒隻有2個線程在執行

控制兩個線程執行順序

public class SemaphoreThread {

    public static void main(String[] args) {
        // 設定公平鎖
        Semaphore semaphore = new Semaphore(1,true);
        // 建立一個緩存線程池
        ExecutorService es = Executors.newCachedThreadPool();
        es.submit( new Thread(() -> {
            String name = Thread.currentThread().getName();
            for (int i = 0; i < 10; i++) {
                try {
                    semaphore.acquire();
                    System.out.println(LocalDateTime.now().toLocalTime()+"  "+name + "正在工作");
                    Thread.sleep(1000);
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }));

        es.submit( new Thread(() -> {
            String name = Thread.currentThread().getName();
            for (int i = 0; i < 10; i++) {
                try {
                    semaphore.acquire();
                    System.out.println(LocalDateTime.now().toLocalTime()+"  "+name + "正在工作");
                    Thread.sleep(100);
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }));

        // 關閉線程池
        es.shutdown();
    }
}
           

輸出:

13:45:11.661  pool-1-thread-1正在工作
13:45:12.662  pool-1-thread-2正在工作
13:45:12.763  pool-1-thread-1正在工作
13:45:13.763  pool-1-thread-2正在工作
13:45:13.863  pool-1-thread-1正在工作
13:45:14.864  pool-1-thread-2正在工作
13:45:14.965  pool-1-thread-1正在工作
13:45:15.965  pool-1-thread-2正在工作
13:45:16.066  pool-1-thread-1正在工作
13:45:17.067  pool-1-thread-2正在工作
13:45:17.167  pool-1-thread-1正在工作
13:45:18.168  pool-1-thread-2正在工作
13:45:18.268  pool-1-thread-1正在工作
13:45:19.268  pool-1-thread-2正在工作
13:45:19.368  pool-1-thread-1正在工作
13:45:20.369  pool-1-thread-2正在工作
13:45:20.470  pool-1-thread-1正在工作
13:45:21.470  pool-1-thread-2正在工作
13:45:21.570  pool-1-thread-1正在工作
13:45:22.571  pool-1-thread-2正在工作
           
從輸出日志可以看出,兩個線程交替執行,這裡的關鍵是設定了信号量公平鎖

繼續閱讀