zoukankan      html  css  js  c++  java
  • 多线程编程(一)-Semaphore(信号量)的使用

    • Semaphore的介绍

        单词Semaphore的中文含义就是信号、信号系统的意思,此类的主要作用就是限制线程并发的数量。

        举个例子,一个屋子里有10个人,但只有一个窄门可以出去,这个窄门一次最多只能通过一人,这样就限制了同时出门的人数,同理也就是限制了线程并发的数量,这也就是Semaphore类要达到的目的。

    • 类Semaphore的同步性

        多线程中的同步就是多个线程排队去执行任务,一个一个执行,不会有线程安全的问题。

        构造函数参数permits是许可的意思,代表同一时间内,最多允许多少个线程同时执行acquire()和release()之间的代码。

        无参方法acquire()的作用是默认使用1个许可。

    package com.wjg.unit1;
    
    import java.util.concurrent.Semaphore;
    
    public class Service {
        private Semaphore semaphore = new Semaphore(1);
        public void testMethod(){
            try {
                semaphore.acquire();
                System.out.println(Thread.currentThread().getName()+" begin timer="+System.currentTimeMillis());
                Thread.sleep(5000);
                System.out.println(Thread.currentThread().getName()+" end   timer="+System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                semaphore.release();
            }
            
        }
    }
    
    //运行类
    package com.wjg.unit1;
    
    public class Run {
        public static void main(String[] args) {
            Service service = new Service();
            Run run = new Run();
            ThreadA a = run.new ThreadA(service);
            a.setName("a");
            a.start();
            
            ThreadB b = run.new ThreadB(service);
            b.setName("b");
            b.start();
            
            ThreadC c = run.new ThreadC(service);
            c.setName("c");
            c.start();
            
        }
        
        public class ThreadA extends Thread {
    
            private Service service;
    
            public ThreadA(Service service) {
                super();
                this.service = service;
            }
    
            @Override
            public void run() {
                service.testMethod();
            }
        }
    
        public class ThreadB extends Thread {
    
            private Service service;
    
            public ThreadB(Service service) {
                super();
                this.service = service;
            }
    
            @Override
            public void run() {
                service.testMethod();
            }
        }
    
        public class ThreadC extends Thread {
    
            private Service service;
    
            public ThreadC(Service service) {
                super();
                this.service = service;
            }
    
            @Override
            public void run() {
                service.testMethod();
            }
        }
    }


    运行结果:
    a begin timer=1487748505823
    a end   timer=1487748510826
    b begin timer=1487748510827
    b end   timer=1487748515828
    c begin timer=1487748515828
    c end   timer=1487748520833
    • 构造函数permits参数作用

        参数permits代表同一时间内,最多允许有x个线程可以执行acquire()和release()之间的代码。我们将上例的Service改造一下,Run类不变

    package com.wjg.unit1;
    
    import java.util.concurrent.Semaphore;
    
    public class Service {
        //我们将premits参数值改为2
        private Semaphore semaphore = new Semaphore(2);
        public void testMethod(){
            try {
                semaphore.acquire();
                System.out.println(Thread.currentThread().getName()+" begin timer="+System.currentTimeMillis());
                Thread.sleep(5000);
                System.out.println(Thread.currentThread().getName()+" end   timer="+System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                semaphore.release();
            }
            
        }
    }

    运行结果:
    a begin timer=1487749198356
    b begin timer=1487749198357
    b end   timer=1487749203359
    a end   timer=1487749203359
    c begin timer=1487749203359
    c end   timer=1487749208360
    • 方法acquire(int permits)使用

        方法acquire(int permits)功能就是每调用1次就使用x个许可。

        这个有一点说明一下,acquire方法做的是减法操作,release方法做的是加法操作,构造函数new Semaphore(5)中的5并不是最终的许可数量,仅仅是初始化的状态值,是可以动态改变的。

    • 方法acquireUninterruptibly()使用

        此方法作用是使等待进入acquire()方法的线程,不允许被中断。我们先看一下被中断的例子

        

    package com.wjg.unit1;
    
    import java.util.concurrent.Semaphore;
    
    public class Service {
        private Semaphore semaphore = new Semaphore(1);
        
        public void testMethod(){
            try {
                semaphore.acquire();
                System.out.println(Thread.currentThread().getName()+" begin timer="+System.currentTimeMillis());
                for (int i = 0; i < Integer.MAX_VALUE; i++) {
                    String newString = new String();
                    Math.random();
                }
                System.out.println(Thread.currentThread().getName()+" end   timer="+System.currentTimeMillis());
            } catch (InterruptedException e) {
                System.out.println("线程"+Thread.currentThread().getName()+"进入了catch");
                e.printStackTrace();
            }finally {
                semaphore.release();
            }
        }
    }
    
    
    
    
    package com.wjg.unit1;
    
    public class Run {
        public static void main(String[] args) throws InterruptedException {
            Service service = new Service();
            Run run  = new Run();
            ThreadA a = run.new ThreadA(service);
            a.setName("a");
            a.start();
            
            ThreadB b = run.new ThreadB(service);
            b.setName("b");
            b.start();
            
            Thread.sleep(1000);
            //中断b线程
            b.interrupt();
            System.out.println("main  中断了b");
        }
        
        public class ThreadA extends Thread{
            private Service service;
    
            public ThreadA(Service service) {
                super();
                this.service = service;
            }
    
            @Override
            public void run() {
                service.testMethod();
            }
            
        }
        
        public class ThreadB extends Thread{
            private Service service;
    
            public ThreadB(Service service) {
                super();
                this.service = service;
            }
    
            @Override
            public void run() {
                service.testMethod();
            }
            
        }
    }


    执行结果:
    a begin timer=1487751504264
    main  中断了b
    java.lang.InterruptedException
    线程b进入了catch
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:996)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1303)
        at java.util.concurrent.Semaphore.acquire(Semaphore.java:317)
        at com.wjg.unit1_1_4.Service.testMethod(Service.java:10)
        at com.wjg.unit1_1_4.Run$ThreadB.run(Run.java:46)
    a end   timer=1487751505711

        以上的例子就是把等待获取许可的线程B手动结束了,下面的例子是利用acquireUninterruptibly()方法阻止等待获取许可的线程中断。

    package com.wjg.unit1_1_4;
    
    import java.util.concurrent.Semaphore;
    
    public class Service {
        private Semaphore semaphore = new Semaphore(1);
        
        public void testMethod(){
            try {
           //此处阻止等待获取许可的线程被中断 semaphore.acquireUninterruptibly(); System.out.println(Thread.currentThread().getName()
    +" begin timer="+System.currentTimeMillis()); for (int i = 0; i < Integer.MAX_VALUE/50; i++) { String newString = new String(); Math.random(); } System.out.println(Thread.currentThread().getName()+" end timer="+System.currentTimeMillis()); } finally { semaphore.release(); } } }


    执行结果
    a begin timer=1487751777062
    main  中断了b
    a end   timer=1487751778455
    b begin timer=1487751778455
    b end   timer=148775177963
    • 方法availablePermits()和drainPermits()使用

        availablePermits()   返回Semaphore对象中当前可用的许可数

        drainPermits()      获取并返回立即可用的许可个数,并且将可用许可置0

    • 方法getQueueLength()和hasQueuedThreads()使用

        getQueueLength()   返回等待可续的线程个数

        hasQueuedThreads()   判断是否还有等待许可的线程

        这两个方法通常都是在判断当前有没有等待许可的线程信息时使用。

    • 公平与非公平信号量

        公平信号量是指获得锁的顺序与线程启动的顺序有关,非公平信息量就是无关的了。

        非公平信号量线程启动的顺序与调用semaphore.acquire()的顺序无关,也就是线程先启动了并不代表先获得许可。

        公平与不公平通过Semaphore类的构造函数new Semaphore(int permits,boolean fair)的第二个参数fair决定。

    • 方法tryAcquire()作用

        无参的tryAcquire()作用就是尝试地获得一个许可,如果获取不到则返回false,此方法通常与if语句结合使用,具有不阻塞的特点。

    • 方法tryAcquire(int permits)使用

       作用是尝试获取x个许可,如果湖区不到则返回false。

    • 方法tryAcquire(long timeout,TimeUnit unit)使用

         作用是在指定的时间内尝试地获取1个许可,如果获取不到则返回false,此处会有阻塞。

    • 方法tryAcquire(int permits,long timeout,TimeUnit unit)使用

        作用是在指定的时间内尝试地获取x个许可,如果获取不到则返回false,此处会有阻塞。    

    注:本系列笔记均参考自《Java并发编程 核心方法与框架》此书。

  • 相关阅读:
    STM32启动BOOT0 BOOT1设置方法
    端口映射
    端口映射
    静态路由配置
    静态路由配置
    NETGEAR路由器登录不上 重新获取ip
    NETGEAR路由器登录不上 重新获取ip
    GSM AT指令 SIM900A TC35
    GSM AT指令 SIM900A TC35
    TTP223 触摸按键
  • 原文地址:https://www.cnblogs.com/niceplay/p/6428934.html
Copyright © 2011-2022 走看看