JAVA多线程之——Semaphore

来源:互联网 发布:android 彩票app源码 编辑:程序博客网 时间:2024/05/18 03:12

Semaphore

一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。
其实Semaphore就是维护了一个共享锁,通过state来决定同时可以多少个线程获取共享锁。

public void acquire() throws InterruptedException {    sync.acquireSharedInterruptibly(1);}

acquire就是获取共享锁。
acquireSharedInterruptibly

public final void acquireSharedInterruptibly(int arg)         throws InterruptedException {     if (Thread.interrupted())  //线程被中断抛出中断异常         throw new InterruptedException();     if (tryAcquireShared(arg) < 0)   //尝试获取锁         doAcquireSharedInterruptibly(arg);//调用方法doAcquireSharedInterruptibly }

doAcquireSharedInterruptibly

private void doAcquireSharedInterruptibly(int arg)       throws InterruptedException {       final Node node = addWaiter(Node.SHARED);//// 创建”当前线程“的Node节点,且Node中记录的锁是”共享锁“类型;并将该节点添加到CLH队列末尾。       boolean failed = true;       try {           for (;;) {               final Node p = node.predecessor(); //获取前一个节点               if (p == head) {  //如果上一个节点是头节点                   int r = tryAcquireShared(arg);//尝试获取锁(上一个是头节点,那么可能此时上一个节点已经成功获取了锁,所以尝试获取一下)                   if (r >= 0) {   //获取成功                       setHeadAndPropagate(node, r); //设置头节点                       p.next = null; // help GC                       failed = false;                       return;                   }               }               // 当前线程一直等待,直到获取到共享锁。            // 如果线程在等待过程中被中断过,则再次中断该线程(还原之前的中断状态)。               if (shouldParkAfterFailedAcquire(p, node) &&                   parkAndCheckInterrupt())                   throw new InterruptedException();           }       } finally {           if (failed)               cancelAcquire(node);       }   }

因此Semaphore就是同时可以让多个线程去获取共享锁,如果线程达到指定阀值,那么就等待,一直等到其它线程调用了release释放。
所以,Semaphore经常用来控制公共资源的并发访问。比如对某一个文件限制只能同时10个线程进行读取。

public class SemaphoreTest {    static Semaphore semaphore = new Semaphore(10);    public static void main(String[] args) {        for(int i = 0 ; i < 100; i++) {           new ReadFile().start();        }    }    static class ReadFile extends Thread{        @Override        public void run() {            try {                semaphore.acquire();                System.out.println(Thread.currentThread().getName() + "开始读取文件");                Thread.currentThread().sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }finally{                // System.out.println(Thread.currentThread().getName() + "释放了一个许可");                 //semaphore.release();            }        }    }}

某次运行结果:

Thread-0开始读取文件Thread-1开始读取文件Thread-4开始读取文件Thread-2开始读取文件Thread-3开始读取文件Thread-5开始读取文件Thread-7开始读取文件Thread-9开始读取文件Thread-6开始读取文件Thread-8开始读取文件

结果是只有是个线程开始读取,其它线程都在等待,没有打印出来。如果把上面的注释代码去掉。那么有释放锁,就会让其它线程可以读取。

0 0
原创粉丝点击