多线程之Semaphore

简介

Semaphore有两个构造方法 Semaphore(int)、Semaphore(int,boolean),参数中的int表示该信号量拥有的许可数量,boolean表示获取许可的时候是否是公平的,如果是公平的那么,当有多个线程要获取许可时,会按照线程来的先后顺序分配许可,否则,线程获得许可的顺序是不定的。这里在jdk中讲到 “一般而言,非公平时候的吞吐量要高于公平锁”,这是为什么呢?

  • 非公平锁性能高于公平锁性能的原因:在恢复一个被挂起的线程与该线程真正运行之间存在着严重的延迟。假设线程A持有一个锁,并且线程B请求这个锁。由于锁被A持有,因此B将被挂起。当A释放锁时,B将被唤醒,因此B会再次尝试获取这个锁。与此同时,如果线程C也请求这个锁,那么C很可能会在B被完全唤醒之前获得、使用以及释放这个锁。这样就是一种双赢的局面:B获得锁的时刻并没有推迟,C更早的获得了锁,并且吞吐量也提高了。当持有锁的时间相对较长或者请求锁的平均时间间隔较长,应该使用公平锁。在这些情况下,插队带来的吞吐量提升(当锁处于可用状态时,线程却还处于被唤醒的过程中)可能不会出现。

但是需要注意,信号量更像是一个计数的装置,而不是一个资源的管理中心。
acquire将计数减1,直到减到0,就会发生阻塞。release将计数加1。release的行为是没有限制的,你可以通过release持续的增加计数,不管之前是否有调用过acquire。所以,初始的许可证个数并不代表上限,通过release可以让许可证的个数超过这个初始值。


Semaphore公共方法

  • void acquire()

    请求一个许可证,如果没有就阻塞,直到有可用的许可证,或者线程被中断。


  • void acquire(int permits)
    请求给定数量的许可证,如果没有就阻塞,直到有足够数量可用的许可证,或者线程被中断。

  • int drainPermits()
    获取所有许可数,并且返回所有许可数

  • void acquireUninterruptibly()
    功能同acquire(),但是不会被中断。如果在阻塞期间线程中断,阻塞依然会继续下去。

  • void acquireUninterruptibly(int permits)
    你懂的。

  • boolean tryAcquire()
    尝试获取一个许可证,如果有就返回true,否则返回false,不会发生阻塞。

  • boolean tryAcquire(long timeout, TimeUnit unit)

    尝试获取一个许可证,如果有就返回true。如果没有就尝试等待给定的时间,在这个时间内线程阻塞,直到有可用的许可证或者超时或者线程中断。


  • void release()
    释放一个许可证,将它交还给信号量。

  • void release(int permits)

    释放指定个数的许可证,将它们交还给信号量。




Semaphore自定义一个显示锁


/**
 * Semaphore自定义一个显示锁
 * new Semaphore(int i)表示允许有i个线程同时拥有这把锁
 */
public class SemaphoreTest1 {

    public static void main(String[] args) {
        final SemaphoreLock lock = new SemaphoreLock();
        for (int i = 0; i < 4; i++) {
            new Thread() {
                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName() + "running");
                        lock.lock();
                        TimeUnit.MILLISECONDS.sleep(2);
                        System.out.println(Thread.currentThread().getName() + "get lock");
                        TimeUnit.SECONDS.sleep(2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        lock.unlock();
                        System.out.println(Thread.currentThread().getName() + "relase lock");
                    }
                }
            }.start();
        }

    }


    static class SemaphoreLock {
        private final Semaphore semaphore = new Semaphore(1);

        public void lock() throws InterruptedException {
            semaphore.acquire();
        }

        public void unlock() {
            semaphore.release();
        }
    }
}

acquire()被打断

public class SemaphoreTest3 {

    public static void main(String[] args) throws InterruptedException {
        final Semaphore semaphore = new Semaphore(1);
        ThreadLocal<Thread> local = new ThreadLocal<>();
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                try {
                    semaphore.acquire();
                    System.out.println("进入t1");
                    while (true) {
                        long i = 0;
                        i++;
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println("t1异常");
                } finally {
                    semaphore.release();
                    System.out.println("释放t2");
                }
            }
        };

        Thread t2 = new Thread("t2") {
            @Override
            public void run() {
                try {
                    semaphore.acquire();
                    local.set(Thread.currentThread());
                    System.out.println("进入t2");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println("t2异常");
                } finally {
                    System.out.println("t2即将释放:" + local.get());
                    if (Thread.currentThread() == local.get()) { //保证自己获得了信号量,才能释放信号量
                        semaphore.release();
                        System.out.println("t2释放:" + local.get());
                    }

                }
            }
        };

        Thread t3 = new Thread("t3") {
            @Override
            public void run() {
                try {
                    semaphore.acquire();
                    System.out.println("进入t3");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println("t3异常");
                } finally {
                    semaphore.release();
                }
            }
        };

        t1.start();
        TimeUnit.MILLISECONDS.sleep(50);
        t2.start();
        TimeUnit.MILLISECONDS.sleep(50);
        t3.start();
        TimeUnit.MILLISECONDS.sleep(50);
        /**
         * 等待获取 信号量 的线程才会被打断
         * 已经获取到 信号量 未结束的线程 不会被打断
         */
        t1.interrupt();
        t2.interrupt();
        t3.interrupt();
        /**
         * semaphore.acquire()换成semaphore.acquireUninterruptibly();
         * 功能同acquire(),但是不会被中断。如果在阻塞期间线程中断,阻塞依然会继续下去。
         */
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值