9.semaphore

十年热恋 提交于 2020-02-03 03:22:12
semaphore信号量

控制同时访问某个特定资源的线程数量,用在流量控制

这像是一种锁的机制,acquire()像是获取锁的机制,这里我们叫他许可证,如果获取不到则阻塞,但是一般锁只允许一个线程同时访问,而semaphore可以同时多个(只要有许可证的存在),当业务执行完毕,你需要增加许可证的个数,当然了,你也可以不增加,但是这样的业务需求似乎不存在,release()可新增一个许可证。

下面模拟数据库链接的代码演示:

package semaphore;

import java.sql.Connection;
import java.util.LinkedList;
import java.util.concurrent.Semaphore;
public class DBPoolSemaphore {
   
   private final static int POOL_SIZE = 10;
   private final Semaphore useful,useless;//useful表示可用的数据库连接,useless表示已用的数据库连接
   
   public DBPoolSemaphore() {
      this. useful = new Semaphore(POOL_SIZE);//10个可用的许可证
      this.useless = new Semaphore(0);//0个不可用的许可证
   }
   
   //存放数据库连接的容器
   private static LinkedList<Connection> pool = new LinkedList<Connection>();
   //初始化池
   static {
        for (int i = 0; i < POOL_SIZE; i++) {//初始化存放10个连接器
            pool.addLast(SqlConnectImpl.fetchConnection());
        }
   }

   /*归还连接*/
   public void returnConnect(Connection connection) throws InterruptedException {
      if(connection!=null) {
         System.out.println("当前有"+useful.getQueueLength()+"个线程等待数据库连接!!"
               +"可用连接数:"+useful.availablePermits());
         useless.acquire();//获取不可用的许可
         synchronized (pool) {
            pool.addLast(connection);
         }  
         useful.release();//可用新增许可
      }
   }
   
   /*从池子拿连接*/
   public Connection takeConnect() throws InterruptedException {
      useful.acquire();//消费一个许可,没有则阻塞(可用数量减少)
      Connection conn;
      synchronized (pool) {
         conn = pool.removeFirst();
      }
      useless.release();//新增一个许可(不可用数量增加)
      return conn;
   }
   
}
package semaphore;
import java.sql.Connection;
import java.util.Random;
public class AppTest {
   private static DBPoolSemaphore dbPool = new DBPoolSemaphore();
   //业务线程
   private static class BusiThread extends Thread{
      @Override
      public void run() {
         Random r = new Random();//让每个线程持有连接的时间不一样
         long start = System.currentTimeMillis();
         try {
            Connection connect = dbPool.takeConnect();//获取链接
            System.out.println("Thread_"+Thread.currentThread().getId()
                  +"_获取数据库连接共耗时【"+(System.currentTimeMillis()-start)+"】ms.");
            Thread.sleep(100+r.nextInt(100));//模拟业务操作,线程持有连接查询数据
            System.out.println("查询数据完成,归还连接!");
            dbPool.returnConnect(connect);//归还获得的链接
         } catch (InterruptedException e) {
         }
      }
   }
   
   public static void main(String[] args) {
        for (int i = 0; i < 50; i++) {
            Thread thread = new BusiThread();
            thread.start();//开启50个线程去获得链接,然后模拟业务,然后归还链接
        }
   }
   
}

结果:

Thread_12_获取数据库连接共耗时【0】ms.
Thread_16_获取数据库连接共耗时【0】ms.
Thread_17_获取数据库连接共耗时【0】ms.
Thread_18_获取数据库连接共耗时【0】ms.
Thread_15_获取数据库连接共耗时【0】ms.
Thread_14_获取数据库连接共耗时【0】ms.
Thread_13_获取数据库连接共耗时【0】ms.
Thread_9_获取数据库连接共耗时【0】ms.
Thread_11_获取数据库连接共耗时【0】ms.
Thread_10_获取数据库连接共耗时【0】ms.
查询数据完成,归还连接!
当前有40个线程等待数据库连接!!可用连接数:0
Thread_19_获取数据库连接共耗时【116】ms.
查询数据完成,归还连接!
当前有39个线程等待数据库连接!!可用连接数:0
Thread_20_获取数据库连接共耗时【124】ms.
查询数据完成,归还连接!
当前有38个线程等待数据库连接!!可用连接数:0
Thread_21_获取数据库连接共耗时【140】ms.
查询数据完成,归还连接!
当前有37个线程等待数据库连接!!可用连接数:0
Thread_22_获取数据库连接共耗时【159】ms.
查询数据完成,归还连接!
当前有36个线程等待数据库连接!!可用连接数:0
Thread_23_获取数据库连接共耗时【161】ms.
查询数据完成,归还连接!
当前有35个线程等待数据库连接!!可用连接数:0
Thread_24_获取数据库连接共耗时【173】ms.
查询数据完成,归还连接!
当前有34个线程等待数据库连接!!可用连接数:0
Thread_25_获取数据库连接共耗时【174】ms.
查询数据完成,归还连接!
当前有33个线程等待数据库连接!!可用连接数:0
Thread_26_获取数据库连接共耗时【175】ms.
查询数据完成,归还连接!
当前有32个线程等待数据库连接!!可用连接数:0
Thread_27_获取数据库连接共耗时【177】ms.
查询数据完成,归还连接!
当前有31个线程等待数据库连接!!可用连接数:0
Thread_29_获取数据库连接共耗时【191】ms.
查询数据完成,归还连接!
当前有30个线程等待数据库连接!!可用连接数:0
Thread_28_获取数据库连接共耗时【256】ms.
查询数据完成,归还连接!
当前有29个线程等待数据库连接!!可用连接数:0
Thread_30_获取数据库连接共耗时【266】ms.
查询数据完成,归还连接!
当前有28个线程等待数据库连接!!可用连接数:0
Thread_31_获取数据库连接共耗时【278】ms.
查询数据完成,归还连接!
当前有27个线程等待数据库连接!!可用连接数:0
Thread_33_获取数据库连接共耗时【284】ms.
查询数据完成,归还连接!
当前有26个线程等待数据库连接!!可用连接数:0
Thread_32_获取数据库连接共耗时【303】ms.
查询数据完成,归还连接!
当前有25个线程等待数据库连接!!可用连接数:0
Thread_34_获取数据库连接共耗时【308】ms.
查询数据完成,归还连接!
当前有24个线程等待数据库连接!!可用连接数:0
Thread_35_获取数据库连接共耗时【337】ms.
查询数据完成,归还连接!
当前有23个线程等待数据库连接!!可用连接数:0
Thread_36_获取数据库连接共耗时【352】ms.
查询数据完成,归还连接!
当前有22个线程等待数据库连接!!可用连接数:0
Thread_37_获取数据库连接共耗时【366】ms.
查询数据完成,归还连接!
当前有21个线程等待数据库连接!!可用连接数:0
Thread_38_获取数据库连接共耗时【371】ms.
查询数据完成,归还连接!
当前有20个线程等待数据库连接!!可用连接数:0
Thread_39_获取数据库连接共耗时【397】ms.
查询数据完成,归还连接!
当前有19个线程等待数据库连接!!可用连接数:0
Thread_40_获取数据库连接共耗时【409】ms.
查询数据完成,归还连接!
当前有18个线程等待数据库连接!!可用连接数:0
Thread_41_获取数据库连接共耗时【422】ms.
查询数据完成,归还连接!
查询数据完成,归还连接!
当前有17个线程等待数据库连接!!可用连接数:0
当前有17个线程等待数据库连接!!可用连接数:0
Thread_42_获取数据库连接共耗时【439】ms.
Thread_43_获取数据库连接共耗时【439】ms.
查询数据完成,归还连接!
当前有15个线程等待数据库连接!!可用连接数:0
Thread_44_获取数据库连接共耗时【453】ms.
查询数据完成,归还连接!
当前有14个线程等待数据库连接!!可用连接数:0
Thread_45_获取数据库连接共耗时【475】ms.
查询数据完成,归还连接!
当前有13个线程等待数据库连接!!可用连接数:0
Thread_46_获取数据库连接共耗时【479】ms.
查询数据完成,归还连接!
当前有12个线程等待数据库连接!!可用连接数:0
Thread_48_获取数据库连接共耗时【499】ms.
查询数据完成,归还连接!
当前有11个线程等待数据库连接!!可用连接数:0
Thread_47_获取数据库连接共耗时【525】ms.
查询数据完成,归还连接!
当前有10个线程等待数据库连接!!可用连接数:0
Thread_49_获取数据库连接共耗时【559】ms.
查询数据完成,归还连接!
当前有9个线程等待数据库连接!!可用连接数:0
Thread_50_获取数据库连接共耗时【560】ms.
查询数据完成,归还连接!
当前有8个线程等待数据库连接!!可用连接数:0
Thread_51_获取数据库连接共耗时【564】ms.
查询数据完成,归还连接!
查询数据完成,归还连接!
当前有7个线程等待数据库连接!!可用连接数:0
当前有7个线程等待数据库连接!!可用连接数:0
Thread_52_获取数据库连接共耗时【566】ms.
Thread_53_获取数据库连接共耗时【566】ms.
查询数据完成,归还连接!
当前有5个线程等待数据库连接!!可用连接数:0
Thread_54_获取数据库连接共耗时【571】ms.
查询数据完成,归还连接!
当前有4个线程等待数据库连接!!可用连接数:0
Thread_55_获取数据库连接共耗时【633】ms.
查询数据完成,归还连接!
当前有3个线程等待数据库连接!!可用连接数:0
Thread_56_获取数据库连接共耗时【634】ms.
查询数据完成,归还连接!
当前有2个线程等待数据库连接!!可用连接数:0
Thread_57_获取数据库连接共耗时【679】ms.
查询数据完成,归还连接!
当前有1个线程等待数据库连接!!可用连接数:0
Thread_58_获取数据库连接共耗时【681】ms.
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:0
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:1
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:2
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:3
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:4
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:5
查询数据完成,归还连接!
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:6
当前有0个线程等待数据库连接!!可用连接数:6
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:8
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:9

SqlConnectImpl.fetchConnection()是一个实现Connection接口的类,没有太大的操作。

注意:acquire();默认使用了一个,即还剩下9个,所以你看到的不是10.(这是百度告诉我的,我也惊呆了)

availablePermits():获取许可证的个数,也就是流量的个数。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!