Semaphore信号量模型,是一种通过维护计数器数值来控制并发数量的模型,Lock实现的互斥锁只允许一个线程访问临界区,而Semaphore允许有限多个线程访问临界区。
什么情况需要允许多个线程同时访问?最常见的需求就是池化资源,连接池、线程池、对象池等等。
java.util.concurren.Semaphore 是JDK中的实现类,常用方法有这些:
1 2 3 public Semaphore (int permits ) ;public void acquire () throws InterruptedException;public void release () ;
构造函数可以传入permits,设置计数器的初始值,表示可以同时获取锁的线程数。 acquire函数用于获取锁,release相反。
下面利用Semaphore实现一个对象池,里面可以存放任意需要复用的对象,如果存放的是连接对象,就变成了连接池。 下面例子往对象池存放了几个字符串对象,再用若干线程同时去申请这个字符串资源。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package io.github.liam8.conimport java.text.SimpleDateFormat import java.util.Date import java.util.concurrent.{ConcurrentLinkedDeque , Semaphore , TimeUnit }import collection.JavaConversions ._object SemaphoreDemo { def main (args: Array [String ]): Unit = { val pool = new SemaphoreDemo [String ](2 , List ("aaaa" , "bbbbb" )) val formatDate = (date: Date ) => new SimpleDateFormat ("HH:mm:ss.SSS" ).format(date) for (i <- 1 to 10 ) { new Thread { override def run (): Unit = { pool.exec { e => println(s"${formatDate(new Date)} thread $i using $e " ) TimeUnit .SECONDS .sleep(3 ) println(s"${formatDate(new Date)} thread $i done with $e " ) } } }.start() } } } class SemaphoreDemo [T ](size: Int , items: List [T ] ) { val pool: ConcurrentLinkedDeque [T ] = new ConcurrentLinkedDeque [T ](items) val semaphore: Semaphore = new Semaphore (size) def exec (func: T => Unit ): Unit = { semaphore.acquire() val t = pool.pop() try { func(t) } finally { pool.add(t) semaphore.release() } } }
output
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 09:56:52.313 thread 4 using bbbbb 09:56:52.313 thread 2 using aaaa 09:56:55.351 thread 2 done with aaaa 09:56:55.351 thread 4 done with bbbbb 09:56:55.352 thread 1 using aaaa 09:56:55.352 thread 3 using bbbbb 09:56:58.353 thread 1 done with aaaa 09:56:58.353 thread 3 done with bbbbb 09:56:58.353 thread 5 using bbbbb 09:56:58.353 thread 6 using aaaa 09:57:01.354 thread 6 done with aaaa 09:57:01.354 thread 5 done with bbbbb 09:57:01.355 thread 7 using aaaa 09:57:01.355 thread 8 using bbbbb 09:57:04.359 thread 7 done with aaaa 09:57:04.359 thread 8 done with bbbbb 09:57:04.360 thread 9 using aaaa 09:57:04.360 thread 10 using bbbbb 09:57:07.363 thread 9 done with aaaa 09:57:07.363 thread 10 done with bbbbb
本文代码 Github仓库