Java多线程中Semaphore对象的用途

Semaphore对象我们可以使用的方法如下:

/*
    semaphore.acquire()
    semaphore.acquire(int permits)

    semaphore.tryAcquire()
    semaphore.tryAcquire(int permits)
    semaphore.tryAcquire(long timeout, TimeUnit unit)

    semaphore.release()
    semaphore.release(int permits)

    semaphore.acquireUninterruptibly()
    semaphore.acquireUninterruptibly(int permits)

    semaphore.availablePermits()
    semaphore.drainPermits()
    semaphore.getQueueLength()
    semaphore.hasQueuedThreads()
    semaphore.isFair()

    semaphore.wait()
    semaphore.wait(long timeout)
    semaphore.wait(long timeout, int nanos)
    semaphore.notify()
    semaphore.notifyAll()
*/

范例1:

package com.contoso;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreExample1 {

    public static void main(String[] args) {

        ExecutorService executor = Executors.newCachedThreadPool();
        Semaphore semaphore = new Semaphore(3);// 初始化许可证计数器,3个许可证表示允许并发线程的个数等于3
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

        Runnable t = () -> {
            try {
                System.out.println(Thread.currentThread().getName() + " before acquire() " + formatter.format(new Date()));
                // 如果一旦有1个线程调用acquire()方法,那么许可证计数器就会减1,
                // 当计数器从3累减0时,其它线程都会被阻塞,只有获得许可证的这3个线程会同时执行
                semaphore.acquire(); 
                System.out.println(Thread.currentThread().getName() + " after acquire() " + formatter.format(new Date()));
                Thread.sleep(2000); // 模拟工作线程需要的时间
                System.out.println(Thread.currentThread().getName() + " work finished " + formatter.format(new Date()));

            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                // 释放全部线程持有的许可证,让许可证计数器重新归位到3个许可证
                // 如此往复地执行完全部的线程
                semaphore.release(); 
            }
        };
        for (int i = 0; i < 10; i++) {
            executor.execute(t);
        }

        executor.shutdown();

    }
}
run:
pool-1-thread-1 before acquire() 2019-10-23 15:01:57.122
pool-1-thread-1 after acquire() 2019-10-23 15:01:57.124
pool-1-thread-2 before acquire() 2019-10-23 15:01:57.124
pool-1-thread-2 after acquire() 2019-10-23 15:01:57.125
pool-1-thread-6 before acquire() 2019-10-23 15:01:57.126
pool-1-thread-6 after acquire() 2019-10-23 15:01:57.126
pool-1-thread-5 before acquire() 2019-10-23 15:01:57.126
pool-1-thread-4 before acquire() 2019-10-23 15:01:57.126
pool-1-thread-3 before acquire() 2019-10-23 15:01:57.125
pool-1-thread-8 before acquire() 2019-10-23 15:01:57.128
pool-1-thread-7 before acquire() 2019-10-23 15:01:57.128
pool-1-thread-9 before acquire() 2019-10-23 15:01:57.129
pool-1-thread-10 before acquire() 2019-10-23 15:01:57.129
pool-1-thread-1 work finished 2019-10-23 15:01:59.125
pool-1-thread-5 after acquire() 2019-10-23 15:01:59.125
pool-1-thread-2 work finished 2019-10-23 15:01:59.127
pool-1-thread-4 after acquire() 2019-10-23 15:01:59.127
pool-1-thread-6 work finished 2019-10-23 15:01:59.128
pool-1-thread-3 after acquire() 2019-10-23 15:01:59.128
pool-1-thread-5 work finished 2019-10-23 15:02:01.125
pool-1-thread-8 after acquire() 2019-10-23 15:02:01.125
pool-1-thread-4 work finished 2019-10-23 15:02:01.127
pool-1-thread-7 after acquire() 2019-10-23 15:02:01.127
pool-1-thread-3 work finished 2019-10-23 15:02:01.128
pool-1-thread-9 after acquire() 2019-10-23 15:02:01.128
pool-1-thread-8 work finished 2019-10-23 15:02:03.126
pool-1-thread-10 after acquire() 2019-10-23 15:02:03.126
pool-1-thread-7 work finished 2019-10-23 15:02:03.128
pool-1-thread-9 work finished 2019-10-23 15:02:03.129
pool-1-thread-10 work finished 2019-10-23 15:02:05.126
BUILD SUCCESSFUL (total time: 8 seconds)

范例1中控制台打印的输出内容可读性太差,重新分组一下,输出信息可读性会更好

run:
pool-1-thread-1 before acquire() 2019-10-23 15:01:57.122
pool-1-thread-1 after acquire() 2019-10-23 15:01:57.124
pool-1-thread-2 before acquire() 2019-10-23 15:01:57.124
pool-1-thread-6 before acquire() 2019-10-23 15:01:57.126
pool-1-thread-5 before acquire() 2019-10-23 15:01:57.126
pool-1-thread-4 before acquire() 2019-10-23 15:01:57.126
pool-1-thread-3 before acquire() 2019-10-23 15:01:57.125
pool-1-thread-8 before acquire() 2019-10-23 15:01:57.128
pool-1-thread-7 before acquire() 2019-10-23 15:01:57.128
pool-1-thread-9 before acquire() 2019-10-23 15:01:57.129
pool-1-thread-10 before acquire() 2019-10-23 15:01:57.129

pool-1-thread-2 after acquire() 2019-10-23 15:01:57.125
pool-1-thread-6 after acquire() 2019-10-23 15:01:57.126
pool-1-thread-5 after acquire() 2019-10-23 15:01:59.125
pool-1-thread-4 after acquire() 2019-10-23 15:01:59.127
pool-1-thread-3 after acquire() 2019-10-23 15:01:59.128
pool-1-thread-8 after acquire() 2019-10-23 15:02:01.125
pool-1-thread-7 after acquire() 2019-10-23 15:02:01.127
pool-1-thread-9 after acquire() 2019-10-23 15:02:01.128
pool-1-thread-10 after acquire() 2019-10-23 15:02:03.126

pool-1-thread-1 work finished 2019-10-23 15:01:59.125
pool-1-thread-2 work finished 2019-10-23 15:01:59.127
pool-1-thread-6 work finished 2019-10-23 15:01:59.128
pool-1-thread-5 work finished 2019-10-23 15:02:01.125
pool-1-thread-4 work finished 2019-10-23 15:02:01.127
pool-1-thread-3 work finished 2019-10-23 15:02:01.128
pool-1-thread-8 work finished 2019-10-23 15:02:03.126
pool-1-thread-7 work finished 2019-10-23 15:02:03.128
pool-1-thread-9 work finished 2019-10-23 15:02:03.129
pool-1-thread-10 work finished 2019-10-23 15:02:05.126
BUILD SUCCESSFUL (total time: 8 seconds)
范例中相应的这3行代码如果修改成如下这样
Semaphore semaphore = new Semaphore(3); semaphore.acquire(2);semaphore.release(2); 
那么打印输出结果表明 ------ 并发数为1,效率很低
run:
pool-1-thread-1 before acquire() 2019-10-23 17:58:36.799
pool-1-thread-3 before acquire() 2019-10-23 17:58:36.799
pool-1-thread-2 before acquire() 2019-10-23 17:58:36.799
pool-1-thread-5 before acquire() 2019-10-23 17:58:36.800
pool-1-thread-6 before acquire() 2019-10-23 17:58:36.800
pool-1-thread-7 before acquire() 2019-10-23 17:58:36.801
pool-1-thread-10 before acquire() 2019-10-23 17:58:36.801
pool-1-thread-8 before acquire() 2019-10-23 17:58:36.801
pool-1-thread-4 before acquire() 2019-10-23 17:58:36.801
pool-1-thread-9 before acquire() 2019-10-23 17:58:36.801

pool-1-thread-3 after acquire() 2019-10-23 17:58:36.799
pool-1-thread-1 after acquire() 2019-10-23 17:58:38.800
pool-1-thread-2 after acquire() 2019-10-23 17:58:40.800
pool-1-thread-5 after acquire() 2019-10-23 17:58:42.801
pool-1-thread-6 after acquire() 2019-10-23 17:58:44.802
pool-1-thread-7 after acquire() 2019-10-23 17:58:46.802
pool-1-thread-10 after acquire() 2019-10-23 17:58:48.802
pool-1-thread-8 after acquire() 2019-10-23 17:58:50.802
pool-1-thread-4 after acquire() 2019-10-23 17:58:52.803
pool-1-thread-9 after acquire() 2019-10-23 17:58:54.803

pool-1-thread-3 work finished 2019-10-23 17:58:38.800
pool-1-thread-1 work finished 2019-10-23 17:58:40.800
pool-1-thread-2 work finished 2019-10-23 17:58:42.801
pool-1-thread-5 work finished 2019-10-23 17:58:44.802
pool-1-thread-6 work finished 2019-10-23 17:58:46.802
pool-1-thread-7 work finished 2019-10-23 17:58:48.802
pool-1-thread-10 work finished 2019-10-23 17:58:50.802
pool-1-thread-8 work finished 2019-10-23 17:58:52.803
pool-1-thread-4 work finished 2019-10-23 17:58:54.803
pool-1-thread-9 work finished 2019-10-23 17:58:56.804
BUILD SUCCESSFUL (total time: 20 seconds)

范例中相应的这3行代码如果修改成如下这样
Semaphore semaphore = new Semaphore(4); semaphore.acquire(2);semaphore.release(2); 
那么打印输出结果表明 ------ 并发数为2
run:
pool-1-thread-3 before acquire() 2019-10-23 17:53:52.329
pool-1-thread-6 before acquire() 2019-10-23 17:53:52.329
pool-1-thread-9 before acquire() 2019-10-23 17:53:52.330
pool-1-thread-1 before acquire() 2019-10-23 17:53:52.329
pool-1-thread-5 before acquire() 2019-10-23 17:53:52.329
pool-1-thread-4 before acquire() 2019-10-23 17:53:52.329
pool-1-thread-2 before acquire() 2019-10-23 17:53:52.329
pool-1-thread-10 before acquire() 2019-10-23 17:53:52.330
pool-1-thread-7 before acquire() 2019-10-23 17:53:52.330
pool-1-thread-8 before acquire() 2019-10-23 17:53:52.330

pool-1-thread-6 after acquire() 2019-10-23 17:53:52.330
pool-1-thread-3 after acquire() 2019-10-23 17:53:52.330

pool-1-thread-9 after acquire() 2019-10-23 17:53:54.331
pool-1-thread-1 after acquire() 2019-10-23 17:53:54.331

pool-1-thread-5 after acquire() 2019-10-23 17:53:56.332
pool-1-thread-4 after acquire() 2019-10-23 17:53:56.332

pool-1-thread-2 after acquire() 2019-10-23 17:53:58.332
pool-1-thread-10 after acquire() 2019-10-23 17:53:58.333

pool-1-thread-7 after acquire() 2019-10-23 17:54:00.332
pool-1-thread-8 after acquire() 2019-10-23 17:54:00.333

pool-1-thread-3 work finished 2019-10-23 17:53:54.331
pool-1-thread-6 work finished 2019-10-23 17:53:54.331

pool-1-thread-1 work finished 2019-10-23 17:53:56.332
pool-1-thread-9 work finished 2019-10-23 17:53:56.332

pool-1-thread-4 work finished 2019-10-23 17:53:58.332
pool-1-thread-5 work finished 2019-10-23 17:53:58.332

pool-1-thread-2 work finished 2019-10-23 17:54:00.332
pool-1-thread-10 work finished 2019-10-23 17:54:00.333

pool-1-thread-7 work finished 2019-10-23 17:54:02.333
pool-1-thread-8 work finished 2019-10-23 17:54:02.333
BUILD SUCCESSFUL (total time: 10 seconds)

范例中相应的这3行代码如果修改成如下这样
Semaphore semaphore = new Semaphore(4); semaphore.acquire(1);semaphore.release(1); 
那么打印输出结果表明 ------ 并发数为4,性能最好,相当于semaphore.acquire();semaphore.release();
run:
pool-1-thread-2 before acquire() 2019-10-23 18:06:00.337
pool-1-thread-6 before acquire() 2019-10-23 18:06:00.337
pool-1-thread-5 before acquire() 2019-10-23 18:06:00.337
pool-1-thread-3 before acquire() 2019-10-23 18:06:00.337
pool-1-thread-1 before acquire() 2019-10-23 18:06:00.336
pool-1-thread-4 before acquire() 2019-10-23 18:06:00.337
pool-1-thread-8 before acquire() 2019-10-23 18:06:00.338
pool-1-thread-7 before acquire() 2019-10-23 18:06:00.338
pool-1-thread-9 before acquire() 2019-10-23 18:06:00.338
pool-1-thread-10 before acquire() 2019-10-23 18:06:00.338


pool-1-thread-6 after acquire() 2019-10-23 18:06:00.337
pool-1-thread-5 after acquire() 2019-10-23 18:06:00.337
pool-1-thread-2 after acquire() 2019-10-23 18:06:00.337
pool-1-thread-3 after acquire() 2019-10-23 18:06:00.338

pool-1-thread-1 after acquire() 2019-10-23 18:06:02.338
pool-1-thread-4 after acquire() 2019-10-23 18:06:02.338
pool-1-thread-8 after acquire() 2019-10-23 18:06:02.338
pool-1-thread-7 after acquire() 2019-10-23 18:06:02.339

pool-1-thread-9 after acquire() 2019-10-23 18:06:04.339
pool-1-thread-10 after acquire() 2019-10-23 18:06:04.339

pool-1-thread-5 work finished 2019-10-23 18:06:02.338
pool-1-thread-3 work finished 2019-10-23 18:06:02.338
pool-1-thread-2 work finished 2019-10-23 18:06:02.338
pool-1-thread-6 work finished 2019-10-23 18:06:02.339

pool-1-thread-4 work finished 2019-10-23 18:06:04.339
pool-1-thread-1 work finished 2019-10-23 18:06:04.339
pool-1-thread-7 work finished 2019-10-23 18:06:04.340
pool-1-thread-8 work finished 2019-10-23 18:06:04.340

pool-1-thread-10 work finished 2019-10-23 18:06:06.340
pool-1-thread-9 work finished 2019-10-23 18:06:06.340
BUILD SUCCESSFUL (total time: 6 seconds)

范例2:

package com.contoso;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreExample2 {

    public static void main(String[] args) {

        ExecutorService executor = Executors.newCachedThreadPool();
        Semaphore semaphore = new Semaphore(3);// 初始化许可证计数器,3个许可证表示允许并发线程的个数等于3
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

        Runnable t = () -> {
            try {
                System.out.println(Thread.currentThread().getName() + " before acquire() " + formatter.format(new Date()));
                // 如果一旦有1个线程调用tryAcquire()方法获取锁,那么许可证计数器就会减1,tryAcquire()方法返回true
                // 当计数器从3累减0时,其它线程都会被阻塞,只有获得许可证的这3个线程会同时执行
                if (semaphore.tryAcquire()) {
                    System.out.println(Thread.currentThread().getName() + " after acquire() " + formatter.format(new Date()));
                    Thread.sleep(500); // 模拟工作线程需要的时间
                    System.out.println(Thread.currentThread().getName() + " work finished " + formatter.format(new Date()));
                    semaphore.release(); // 不能写到finally里释放
                    // 释放全部线程持有的许可证,让许可证计数器重新归位到3个许可证
                    // 如此往复地执行后续0.5秒后获得许可证的3个线程
                } else {
                    System.out.println(Thread.currentThread().getName() + " tryAcquire() has no permit " + formatter.format(new Date()));
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } 
        };
        for (int i = 0; i < 20; i++) {
            executor.execute(t);
        }
        executor.shutdown();
    }
控制台打印输出的信息是杂乱的,进行重新归类后的信息很方便大家阅读
run:
pool-1-thread-3 before acquire() 2019-10-23 21:44:38.245
pool-1-thread-2 before acquire() 2019-10-23 21:44:38.245
pool-1-thread-6 before acquire() 2019-10-23 21:44:38.245
pool-1-thread-1 before acquire() 2019-10-23 21:44:38.245
pool-1-thread-5 before acquire() 2019-10-23 21:44:38.247
pool-1-thread-7 before acquire() 2019-10-23 21:44:38.247
pool-1-thread-4 before acquire() 2019-10-23 21:44:38.246
pool-1-thread-8 before acquire() 2019-10-23 21:44:38.248
pool-1-thread-9 before acquire() 2019-10-23 21:44:38.248
pool-1-thread-10 before acquire() 2019-10-23 21:44:38.248
pool-1-thread-13 before acquire() 2019-10-23 21:44:38.248
pool-1-thread-14 before acquire() 2019-10-23 21:44:38.249
pool-1-thread-12 before acquire() 2019-10-23 21:44:38.248
pool-1-thread-15 before acquire() 2019-10-23 21:44:38.249
pool-1-thread-16 before acquire() 2019-10-23 21:44:38.249
pool-1-thread-11 before acquire() 2019-10-23 21:44:38.249
pool-1-thread-20 before acquire() 2019-10-23 21:44:38.249
pool-1-thread-19 before acquire() 2019-10-23 21:44:38.249
pool-1-thread-17 before acquire() 2019-10-23 21:44:38.250
pool-1-thread-18 before acquire() 2019-10-23 21:44:38.250

pool-1-thread-2 after acquire() 2019-10-23 21:44:38.246
pool-1-thread-6 after acquire() 2019-10-23 21:44:38.246
pool-1-thread-3 after acquire() 2019-10-23 21:44:38.246

pool-1-thread-1 tryAcquire() has no permit 2019-10-23 21:44:38.246
pool-1-thread-5 tryAcquire() has no permit 2019-10-23 21:44:38.247
pool-1-thread-7 tryAcquire() has no permit 2019-10-23 21:44:38.247
pool-1-thread-4 tryAcquire() has no permit 2019-10-23 21:44:38.248
pool-1-thread-8 tryAcquire() has no permit 2019-10-23 21:44:38.248
pool-1-thread-9 tryAcquire() has no permit 2019-10-23 21:44:38.248
pool-1-thread-12 tryAcquire() has no permit 2019-10-23 21:44:38.249
pool-1-thread-14 tryAcquire() has no permit 2019-10-23 21:44:38.249
pool-1-thread-13 tryAcquire() has no permit 2019-10-23 21:44:38.249
pool-1-thread-10 tryAcquire() has no permit 2019-10-23 21:44:38.249
pool-1-thread-15 tryAcquire() has no permit 2019-10-23 21:44:38.249
pool-1-thread-16 tryAcquire() has no permit 2019-10-23 21:44:38.249
pool-1-thread-20 tryAcquire() has no permit 2019-10-23 21:44:38.250
pool-1-thread-11 tryAcquire() has no permit 2019-10-23 21:44:38.250
pool-1-thread-19 tryAcquire() has no permit 2019-10-23 21:44:38.250
pool-1-thread-17 tryAcquire() has no permit 2019-10-23 21:44:38.250
pool-1-thread-18 tryAcquire() has no permit 2019-10-23 21:44:38.250

pool-1-thread-3 work finished 2019-10-23 21:44:38.747
pool-1-thread-6 work finished 2019-10-23 21:44:38.747
pool-1-thread-2 work finished 2019-10-23 21:44:38.747
BUILD SUCCESSFUL (total time: 0 seconds)

 

你可能感兴趣的:(Java多线程)