高并发之Semaphore

1.Semaphore作用
synchronized只能让一段代码同步执行,而Semaphore可以控制并发数量
2.Semaphore常用API(构造方法就不说了,就2个挺简单,查下API文档)

methoddescription
void acquire()Acquires a permit from this semaphore, blocking until one is available, or the thread is interrupted
void acquire(int permits)Acquires the given number of permits from this semaphore, blocking until all are available, or the thread is interrupted.
void acquireUninterruptibly()Acquires a permit from this semaphore, blocking until one is available.
void acquireUninterruptibly(int permits)Acquires the given number of permits from this semaphore, blocking until all are available.
int availablePermits()Returns the current number of permits available in this semaphore.
int drainPermits()Acquires and returns all permits that are immediately available.
int getQueueLength()Returns an estimate of the number of threads waiting to acquire.
boolean hasQueuedThreads()Queries whether any threads are waiting to acquire.
boolean isFair()Returns true if this semaphore has fairness set true.
void release()Releases a permit, returning it to the semaphore.
void release(int permits)Releases the given number of permits, returning them to the semaphore.
boolean tryAcquire()Acquires a permit from this semaphore, only if one is available at the time of invocation.
boolean tryAcquire(int permits)Acquires the given number of permits from this semaphore, only if all are available at the time of invocation.
boolean tryAcquire(int permits, long timeout, TimeUnit unit)Acquires the given number of permits from this semaphore, if all become available within the given waiting time and the current thread has not been interrupted.
boolean tryAcquire(long timeout, TimeUnit unit)Acquires a permit from this semaphore, if one becomes available within the given waiting time and the current thread has not been interrupted.

3.详解API用法

  1. acquire

     # acquire(int permits)和acquire()类似,这里就只演示acquire()
     
     public class TempDemo {
         private static Semaphore semaphore = new Semaphore(1);
     
         public static void test() {
             try {
                 semaphore.acquire();
                 System.out.println(Thread.currentThread().getName() + " 开始执行...");
                 // 这里就是让线程在执行中
                 for (int index = 0; index < Integer.MAX_VALUE / 120; index ++) {
                     String ss = new String();
                     Math.random();
                 }
                 System.out.println(Thread.currentThread().getName() + " 执行结束...");
             } catch (InterruptedException e) {
                 e.printStackTrace();
             } finally {
                 semaphore.release();
             }
         }
     
         public static void main(String[] args) throws Exception {
             Thread[] threads = new Thread[5];
             for (int index = 0; index < threads.length; index ++) {
                 threads[index] = new Thread(() -> {
                     test();
                 });
                 threads[index].setName("Thread-" + index);
                 threads[index].start();
             }
             for (int index = 0; index < threads.length; index ++) {
                 threads[index].join();
             }
         }
     }
     		
     注意:acquire()是可以被中断的,例如把线程0中断,线程0就中断执行了:
     Thread[] threads = new Thread[5];
     for (int index = 0; index < threads.length; index ++) {
         threads[index] = new Thread(() -> {
             test();
         });
         threads[index].setName("Thread-" + index);
         threads[index].start();
     }
     threads[0].interrupt(); // 中断线程0
     for (int index = 0; index < threads.length; index ++) {
         threads[index].join();
     }
    
  2. acquireUninterruptibly

     # acquireUninterruptibly和acquire的区别在于,acquireUninterruptibly不可以中断,如下代码虽然有显示的中断,
     但是线程0没有受到影响
     
     public class TempDemo {
         private static Semaphore semaphore = new Semaphore(1);
     
         public static void test() {
             semaphore.acquireUninterruptibly();
             System.out.println(Thread.currentThread().getName() + " 开始执行...");
             // 这里就是让线程在执行中
             for (int index = 0; index < Integer.MAX_VALUE / 120; index ++) {
                 String ss = new String();
                 Math.random();
             }
             System.out.println(Thread.currentThread().getName() + " 执行结束...");
             semaphore.release();
         }
     
         public static void main(String[] args) throws Exception {
             Thread[] threads = new Thread[5];
             for (int index = 0; index < threads.length; index ++) {
                 threads[index] = new Thread(() -> {
                     test();
                 });
                 threads[index].setName("Thread-" + index);
                 threads[index].start();
             }
             threads[0].interrupt();
             for (int index = 0; index < threads.length; index ++) {
                 threads[index].join();
             }
         }
     }
    
  3. tryAcquire

     # tryAcquire(int permits)和tryAcquire类似就不说了
     
     public class TempDemo {
         private static Semaphore semaphore = new Semaphore(1);
     
         public static void test() {
             if (semaphore.tryAcquire()) {
                 System.out.println(Thread.currentThread().getName() + " 开始执行...");
                 // 这里就是让线程在执行中
                 for (int index = 0; index < Integer.MAX_VALUE / 120; index ++) {
                     String ss = new String();
                     Math.random();
                 }
                 System.out.println(Thread.currentThread().getName() + " 执行结束...");
                 semaphore.release();
             } else {
                 System.out.println(Thread.currentThread().getName() + " 没有获取到凭证");
             }
     
         }
     
         public static void main(String[] args) throws Exception {
             Thread[] threads = new Thread[5];
             for (int index = 0; index < threads.length; index ++) {
                 threads[index] = new Thread(() -> {
                     test();
                 });
                 threads[index].setName("Thread-" + index);
                 threads[index].start();
             }
             for (int index = 0; index < threads.length; index ++) {
                 threads[index].join();
             }
         }
     }
    
     # tryAcquire(long timeout, TimeUnit unit) 在规定的时间内获取到凭证就返回,也是可以被中断的
    
  4. release

     # release释放资源,调用几次就释放几个,这个一定要注意,下面这段代码输出的是3
     public class TempDemo {
         private static Semaphore semaphore = new Semaphore(1);
     
         public static void main(String[] args) throws Exception {
             semaphore.release();
             semaphore.release();
             System.out.println("permits: " + semaphore.availablePermits());
         }
     }
    
  5. other

     isFair()就不说了,相对公平而已,个人觉得用处不是很大吧,可能自己了解不够深入
     getQueueLength()估算等待线程数
     hasQueuedThreads()是否有等待线程
     drainPermits()清空permits,并返回permits
    

4.多路进-多处理-多出路

# 也就是多个线程访问一段代码,这段代码多个线程可以同时执行

public class TempDemo {
    private static Semaphore semaphore = new Semaphore(2);

    public static void test() {
        try {
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName() + " 开始执行...");
            // 这里就是让线程在执行中
            for (int index = 0; index < Integer.MAX_VALUE / 120; index ++) {
                String ss = new String();
                Math.random();
            }
            System.out.println(Thread.currentThread().getName() + " 执行结束...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
        }
    }

    public static void main(String[] args) throws Exception {
        Thread[] threads = new Thread[5];
        for (int index = 0; index < threads.length; index ++) {
            threads[index] = new Thread(() -> {
                test();
            });
            threads[index].setName("Thread-" + index);
            threads[index].start();
        }
        for (int index = 0; index < threads.length; index ++) {
            threads[index].join();
        }
    }
}

5.多路进-单处理-多出路

# 看代码吧 挺简单的
public class TempDemo {
    private static Semaphore semaphore = new Semaphore(2);
    private static ReentrantLock lock = new ReentrantLock();

    public static void test() {
        try {
            semaphore.acquire();
            lock.lock();
            System.out.println(Thread.currentThread().getName() + " 开始执行...");
            // 这里就是让线程在执行中
            for (int index = 0; index < Integer.MAX_VALUE / 120; index ++) {
                String ss = new String();
                Math.random();
            }
            System.out.println(Thread.currentThread().getName() + " 执行结束...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            semaphore.release();
        }
    }

    public static void main(String[] args) throws Exception {
        Thread[] threads = new Thread[5];
        for (int index = 0; index < threads.length; index ++) {
            threads[index] = new Thread(() -> {
                test();
            });
            threads[index].setName("Thread-" + index);
            threads[index].start();
        }
        for (int index = 0; index < threads.length; index ++) {
            threads[index].join();
        }
    }
}

6.生产者消费者实现
场景大概是这样的,10个消费者(饭店只能同时5个人吃饭),4厨师,3个服务员,来模拟饭店做菜上菜的生产者消费者模式

public class TempDemo {

    public static void main(String[] args) throws Exception {
        HotelDemo hotelDemo = new HotelDemo(4, 5, 3);
        int threadCount = 10;

        Thread[] producerThreads = new Thread[threadCount];
        Thread[] consumerThreads = new Thread[threadCount];
        for (int index = 0; index < threadCount; index ++) {
            // 生产
            producerThreads[index] = new Thread(() -> {
                hotelDemo.set();
            });
            producerThreads[index].setName("producer-thread-" + index);

            // 消费
            consumerThreads[index] = new Thread(() -> {
                hotelDemo.get();
            });
            consumerThreads[index].setName("consumer-thread-" + index);
        }

        for (int index = 0; index < threadCount; index ++) {
            producerThreads[index].start();
            consumerThreads[index].start();
        }

        for (int index = 0; index < threadCount; index ++) {
            producerThreads[index].join();
            consumerThreads[index].join();
        }
    }
}

class HotelDemo {
    /**
     * 厨师数量
     */
    private volatile Semaphore producers = null;
    /**
     * 厨师菜做好通知
     */
    private volatile ReentrantLock lock = null;
    private volatile Condition sendCondition = null;
    /**
     * 服务员 做好的菜都要放到服务员手里 如果没有多余的服务员厨师就暂时不做菜
     */
    private volatile String[] services = null;
    /**
     * 消费者数量
     */
    private volatile Semaphore consumers = null;
    /**
     * 消费者消耗了菜
     */
    private volatile Condition obtainCondition = null;

    public HotelDemo(int producerCount, int consumerCount, int serviceCount) {
        producers = new Semaphore(producerCount);
        lock = new ReentrantLock();
        sendCondition = lock.newCondition();
        services = new String[serviceCount];
        consumers = new Semaphore(consumerCount);
        obtainCondition = lock.newCondition();
    }

    /**
     * 厨师做菜
     */
    public void set() {
        try {
            producers.acquire();
            lock.lock();
            while (this.isFull()) {
                System.out.println(Thread.currentThread().getName() + " 要做饭 但是服务员不够 ");
                sendCondition.await();
            }

            // 厨师做饭要1秒
            TimeUnit.SECONDS.sleep(1);
            System.out.println(Thread.currentThread().getName() + " 做饭了 ");
            this.add("做饭了");

            obtainCondition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            producers.release();
        }
    }

    /**
     * 消费者消耗菜
     */
    public void get() {
        try {
            consumers.acquire();
            lock.lock();
            while (this.isEmpty()) {
                System.out.println(Thread.currentThread().getName() + " 要吃饭 饭还没有好 ");
                obtainCondition.await();
            }

            // 假设用户吃饭要2秒
            TimeUnit.SECONDS.sleep(2);
            System.out.println(Thread.currentThread().getName() + " 吃饭了");
            this.poll();

            sendCondition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            consumers.release();
        }
    }

    private synchronized void add(String name) {
        for (int index = 0; index < services.length; index ++) {
            if (services[index] == null) {
                services[index] = name;
                return;
            }
        }
    }

    private synchronized boolean isFull() {
        System.out.println(Arrays.asList(services).toString());
        for (int index = 0; index < services.length; index ++) {
            if (services[index] == null) {
                return false;
            }
        }
        return true;
    }

    private synchronized String poll() {
        for (int index = 0; index < services.length; index ++) {
            if (services[index] != null) {
                String temp = services[index];
                services[index] = null;
                return temp;
            }
        }
        return null;
    }

    private synchronized boolean isEmpty() {
        System.out.println(Arrays.asList(services).toString());
        for (int index = 0; index < services.length; index ++) {
            if (services[index] != null) {
                return false;
            }
        }
        return true;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值