什么时候使用countdownlatch 超时

让天下没有难学的技术
并发工具类(一)等待多线程完成的CountDownLatch
并发工具类(一)等待多线程完成的CountDownLatch
CountDownLatch 允许一个或多个线程等待其他线程完成操作。
假如有这样一个需求,当我们需要解析一个Excel里多个sheet的数据时,可以考虑使用多线程,每个线程解析一个sheet里的数据,等到所有的sheet都解析完之后,程序需要提示解析完成。在这个需求中,要实现主线程等待所有线程完成sheet的解析操作,最简单的做法是使用join。代码如下:
public class JoinCountDownLatchTest {
public static void main(String[] args) throws InterruptedException {
Thread parser1 = new Thread(new Runnable() {
public void run() {
Thread parser2 = new Thread(new Runnable() {
public void run() {
System.out.println(&parser2 finish&);
parser1.start();
parser2.start();
parser1.join();
parser2.join();
System.out.println(&all parser finish&);
join用于让当前执行线程等待join线程执行结束。其实现原理是不停检查join线程是否存活,如果join线程存活则让当前线程永远wait,代码片段如下,wait(0)表示永远等待下去。
while (isAlive()) {
直到join线程中止后,线程的this.notifyAll会被调用,调用notifyAll是在JVM里实现的,所以JDK里看不到,有兴趣的同学可以看看。JDK不推荐在线程实例上使用wait,notify和notifyAll方法。
而在JDK1.5之后的并发包中提供的CountDownLatch也可以实现join的这个功能,并且比join的功能更多。
&pre&public class CountDownLatchTest {
static CountDownLatch c = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
public void run() {
System.out.println(1);
c.countDown();
System.out.println(2);
c.countDown();
}).start();
c.await();
System.out.println(&3&);
CountDownLatch的构造函数接收一个int类型的参数作为计数器,如果你想等待N个点完成,这里就传入N。
当我们调用一次CountDownLatch的countDown方法时,N就会减1,CountDownLatch的await会阻塞当前线程,直到N变成零。由于countDown方法可以用在任何地方,所以这里说的N个点,可以是N个线程,也可以是1个线程里的N个执行步骤。用在多个线程时,你只需要把这个CountDownLatch的引用传递到线程里。
如果有某个解析sheet的线程处理的比较慢,我们不可能让主线程一直等待,所以我们可以使用另外一个带指定时间的await方法,await(long time, TimeUnit unit): 这个方法等待特定时间后,就会不再阻塞当前线程。join也有类似的方法。
注意:计数器必须大于等于0,只是等于0时候,计数器就是零,调用await方法时不会阻塞当前线程。CountDownLatch不可能重新初始化或者修改CountDownLatch对象的内部计数器的值。一个线程调用countDown方法 happen-before 另外一个线程调用await方法。
原创文章,转载请注明: 转载自本文链接地址:
花名清英,并发网()创始人,畅销书《Java并发编程的艺术》作者,蚂蚁金服技术专家。目前工作于支付宝微贷事业部,关注互联网金融,并发编程和敏捷实践。
Latest posts by 方 腾飞 ()
Related posts:
(3 votes, average: 2.67 out of 5)
Loading...CountDownLatch(int&count)
&&&&&&&&&&Constructs a CountDownLatch initialized with the given
&&&&&&&&&&Causes the current thread to wait until the latch has counted down to
zero, unless the thread is interrupted.
await(long&timeout,
TimeUnit&unit)
&&&&&&&&&&Causes the current thread to wait until the latch has counted down to
zero, unless the thread is interrupted,
or the specified waiting time elapses.
countDown()
&&&&&&&&&&Decrements the count of the latch, releasing all waiting threads if
the count reaches zero.
getCount()
&&&&&&&&&&Returns the current count.
toString()
&&&&&&&&&&Returns a string identifying this latch, as well as its state.
equals, getClass, hashCode, notify, notifyAll, wait, wait, wait
CountDownLatch
public CountDownLatch(int&count)
Constructs a CountDownLatch initialized with the given
参数:count - the number of times countDown() must be invoked
before threads can pass through await().
IllegalArgumentException - if count is less than zero.
public void await()
throws InterruptedException
Causes the current thread to wait until the latch has counted down to
zero, unless the thread is interrupted.
If the current count is zero then this method
returns immediately.
If the current count is greater than zero then
the current thread becomes disabled for thread scheduling
purposes and lies dormant until one of two things happen:
The count reaches zero due to invocations of the
countDown() or
Some other thread interrupts the current
If the current thread:
has its interrupted status set on
is interrupted while waiting,
then InterruptedException is thrown and the current thread's
interrupted status is cleared.
InterruptedException - if the current thread is interrupted
while waiting.
public boolean await(long&timeout,
TimeUnit&unit)
throws InterruptedException
Causes the current thread to wait until the latch has counted down to
zero, unless the thread is interrupted,
or the specified waiting time elapses.
If the current count is zero then this method
returns immediately with the value true.
If the current count is greater than zero then
the current thread becomes disabled for thread scheduling
purposes and lies dormant until one of three things happen:
The count reaches zero due to invocations of the
countDown() or
Some other thread interrupts the current
The specified waiting time elapses.
If the count reaches zero then the method returns with the
value true.
If the current thread:
has its interrupted status set on
is interrupted while waiting,
then InterruptedException is thrown and the current thread's
interrupted status is cleared.
If the specified waiting time elapses then the value false
is returned.
If the time is
less than or equal to zero, the method will not wait at all.
参数:timeout - the maximum time to waitunit - the time unit of the timeout argument.
返回:true if the count reached zero
if the waiting time elapsed before the count reached zero.
InterruptedException - if the current thread is interrupted
while waiting.
public void countDown()
Decrements the count of the latch, releasing all waiting threads if
the count reaches zero.
If the current count is greater than zero then
it is decremented. If the new count is zero then all waiting threads
are re-enabled for thread scheduling purposes.
If the current count equals zero then nothing
public long getCount()
Returns the current count.
This method is typically used for debugging and testing purposes.
返回:the current count.
public String toString()Returns a string identifying this latch, as well as its state.The state, in brackets, includes the String &Count =& followed by the current count.覆盖:类 Object 中的 toString返回:a string identifying this latch, as well as itsstate
JAVA下的CountDownLatch使用方法和示例
上一篇:下一篇:
CountDownLatch相关文章请点击
责任申明:本站内容均整理自互联网,若有侵权,请联系我们。使用本站提供的任务技术内容造成不良后果,本站不负任何责任。
欢迎投稿,电子邮件:(#号换成@)&& QQ群1: &&JAVA基础(12)
CountDownLatch类是一个同步计数器
public boolean await()
如果当前计数大于零,当前线程将一直处于休眠状态;
如果当前计数为零,则释放所有等待的线程,线程进入运行状态。
public void countDown()
public class Worker implements Runnable {
private CountDownLatch downL
public Worker(CountDownLatch downLatch, String name) {
this.downLatch = downL
this.name =
public void run() {
this.doWork();
TimeUnit.SECONDS.sleep(new Random().nextInt(10));
} catch (InterruptedException ie) {
System.out.println(&--------- &+ this.name + &活干完了!&);
this.downLatch.countDown();
private void doWork() {
System.out.println(this.name + & ,正在干活!&);
public class Boss implements Runnable {
private CountDownLatch downL
public Boss(CountDownLatch downLatch) {
this.downLatch = downL
public void run() {
System.out.println(&老板正在等所有的工人干完活......&);
this.downLatch.await();
} catch (InterruptedException e) {
System.out.println(&工人活都干完了,老板开始检查了!&);
public class CountDownLatchDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
CountDownLatch latch = new CountDownLatch(3);
Worker w1 = new Worker(latch, &张三&);
Worker w2 = new Worker(latch, &李四&);
Worker w3 = new Worker(latch, &王二&);
Boss boss = new Boss(latch);
executor.execute(w3);
executor.execute(w2);
executor.execute(w1);
executor.execute(boss);
executor.shutdown();
当你运行CountDownLatchDemo这个对象的时候,你会发现是等所有的工人都干完了活,老板才来检查,下面是我本地机器上运行的一次结果,可以肯定的每次运行的结果可能与下面不一样,但老板检查永远是在后面的。
运行结果:
-----------------------------------------------------
王二 ,正在干活!
老板正在等所有的工人干完活......
张三 ,正在干活!
李四 ,正在干活!
--------- 张三活干完了!
--------- 李四活干完了!
--------- 王二活干完了!
工人活都干完了,老板开始检查了!
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
(1)(1)(1)(2)(4)(1)(2)(10)(1)(13)(7)(9)(12)(1)(1)(7)(2)(1)(5)(1)(3)(6)(1)人气:113858
访问用户量:436
笔记经验:99
总积分:1409
级别:普通会员
搜索本笔记
ta的交流分类
ta的全部笔记
浏览(6702)|(0)
&&交流分类:|笔记分类:
学习笔记 - java.util.concurrent 多线程框架
下面先整理一下与多线程相关的知识: JDK5中的一个亮点就是将的引入到Java标准库中。
package import java.util.concurrent.ExecutorS import java.util.concurrent.E public class TestThreadPool { public static void main(String args[]) throws InterruptedException { // only two threads ExecutorService exec = Executors.newFixedThreadPool(2); for(int index = 0; index & 100; index++) { Runnable run = new Runnable() { public void run() { long time = (long) (Math.random() * 1000); System.out.println(“Sleeping ” + time + “ms”); try { Thread.sleep(time); } catch (InterruptedException e) { } } }; exec.execute(run); } // must shutdown exec.shutdown(); } }
上面是一个简单的例子,使用了2个大小的线程池来处理100个线程。但有一个问题:在for循环的过程中,会等待线程池有空闲的线程, 所以主线程会阻塞的。为了解决这个问题,一般启动一个线程来做for循环,就是为了避免由于线程池满了造成主线程阻塞。不过在这里我没有这样处理。[重要 修正:经过测试,即使线程池大小小于实际线程数大小,线程池也不会阻塞的,这与Tomcat的线程池不同,它将Runnable实例放到一个“无限”的 BlockingQueue中,所以就不用一个线程启动for循环,Doug Lea果然厉害]
另外它使用了Executors的静态函数生成一个固定的线程池,顾名思义,线程池的线程是不会释放的,即使它是Idle。这就会产生 性能问题,比如如果线程池的大小为200,当全部使用完毕后,所有的线程会继续留在池中,相应的内存和线程切换(while(true)+sleep循 环)都会增加。如果要避免这个问题,就必须直接使用ThreadPoolExecutor()来构造。可以像Tomcat的线程池一样设置“最大线程 数”、“最小线程数”和“空闲线程keepAlive的时间”。通过这些可以基本上替换Tomcat的线程池实现方案。
需要注意的是线程池必须使用shutdown来显式关闭,否则主线程就无法退出。shutdown也不会阻塞主线程。
许多长时间运行的应用有时候需要定时运行任务完成一些诸如统计、优化等工作,比如在电信行业中处理用户话单时,需要 每隔1分钟处理话单;网站每天凌晨统计用户访问量、用户数;大型超时凌晨3点统计当天销售额、以及最热卖的商品;每周日进行数据库备份;公司每个月的10 号计算工资并进行转帐等,这些都是定时任务。通过 java的并发库可以轻松的完成这些任务,而且非常的简单。
package import static java.util.concurrent.TimeUnit.SECONDS; import java.util.D import java.util.concurrent.E import java.util.concurrent.ScheduledExecutorS import java.util.concurrent.ScheduledF public class TestScheduledThread { public static void main(String[] args) { final ScheduledExecutorService scheduler = Executors .newScheduledThreadPool(2); final Runnable beeper = new Runnable() { int count = 0; public void run() { System.out.println(new Date() + ” beep ” + (++count)); } }; // 1秒钟后运行,并每隔2秒运行一次 final ScheduledFuture beeperHandle = scheduler.scheduleAtFixedRate( beeper, 1, 2, SECONDS); // 2秒钟后运行,并每次在上次任务运行完后等待5秒后重新运行 final ScheduledFuture beeperHandle2 = scheduler .scheduleWithFixedDelay(beeper, 2, 5, SECONDS); // 30秒后结束关闭任务,并且关闭Scheduler scheduler.schedule(new Runnable() { public void run() { beeperHandle.cancel(true); beeperHandle2.cancel(true); scheduler.shutdown(); } }, 30, SECONDS); } }
为了退出进程,上面的代码中加入了关闭Scheduler的操作。而对于24小时运行的应用而言,是没有必要关闭Scheduler的。
在实际应用中,有时候需要多个线程同时工作以完成同一件事情,而且在完成过程中,往往会等待其他线程都完成某一阶段后再执行,等所有线程都到达某一个阶段后再统一执行。
比如有几个旅行团需要途经深圳、广州、韶关、长沙最后到达武汉。旅行团中有自驾游的,有徒步的,有乘坐旅游大巴的;这些旅行团同时出发,并且每到一个目的地,都要等待其他旅行团到达此地后再同时出发,直到都到达终点站武汉。
这时候就可以派上用场。CyclicBarrier最重要的属性就是参与者个数,另外最要方法是await()。当所有线程都调用了await()后,就表示这些线程都可以继续执行,否则就会等待。
package import java.text.SimpleDateF import java.util.D import java.util.concurrent.BrokenBarrierE import java.util.concurrent.CyclicB import java.util.concurrent.ExecutorS import java.util.concurrent.E public class TestCyclicBarrier { // 徒步需要的时间: Shenzhen, Guangzhou, Shaoguan, Changsha, Wuhan private static int[] timeWalk = { 5, 8, 15, 15, 10 }; // 自驾游 private static int[] timeSelf = { 1, 3, 4, 4, 5 }; // 旅游大巴 private static int[] timeBus = { 2, 4, 6, 6, 7 };
static String now() { SimpleDateFormat sdf = new SimpleDateFormat(“HH:mm:ss”); return sdf.format(new Date()) + “: “; }
static class Tour implements Runnable { private int[] private CyclicB private String tourN public Tour(CyclicBarrier barrier, String tourName, int[] times) { this.times = this.tourName = tourN this.barrier = } public void run() { try { Thread.sleep(times[0] * 1000); System.out.println(now() + tourName + ” Reached Shenzhen”); barrier.await(); Thread.sleep(times[1] * 1000); System.out.println(now() + tourName + ” Reached Guangzhou”); barrier.await(); Thread.sleep(times[2] * 1000); System.out.println(now() + tourName + ” Reached Shaoguan”); barrier.await(); Thread.sleep(times[3] * 1000); System.out.println(now() + tourName + ” Reached Changsha”); barrier.await(); Thread.sleep(times[4] * 1000); System.out.println(now() + tourName + ” Reached Wuhan”); barrier.await(); } catch (InterruptedException e) { } catch (BrokenBarrierException e) { } } }
public static void main(String[] args) { // 三个旅行团 CyclicBarrier barrier = new CyclicBarrier(3); ExecutorService exec = Executors.newFixedThreadPool(3); exec.submit(new Tour(barrier, “WalkTour”, timeWalk)); exec.submit(new Tour(barrier, “SelfTour”, timeSelf)); exec.submit(new Tour(barrier, “BusTour”, timeBus)); exec.shutdown(); } }
运行结果: 00:02:25: SelfTour Reached Shenzhen 00:02:25: BusTour Reached Shenzhen 00:02:27: WalkTour Reached Shenzhen 00:02:30: SelfTour Reached Guangzhou 00:02:31: BusTour Reached Guangzhou 00:02:35: WalkTour Reached Guangzhou 00:02:39: SelfTour Reached Shaoguan 00:02:41: BusTour Reached Shaoguan
并发库中的是一个比较好玩的类,顾名思义,就是阻塞队列。该类主要提供了两个方法put()和take(),前者将一个对象放到队列中,如果队列已经满了,就等待直到有空闲节点;后者从head取一个对象,如果没有对象,就等待直到有可取的对象。
下面的例子比较简单,一个读线程,用于将要处理的文件对象添加到阻塞队列中,另外四个写线程用于取出文件对象,为了模拟写操作耗时长的 特点,特让线程睡眠一段随机长度的时间。另外,该Demo也使用到了线程池和原子整型(AtomicInteger),AtomicInteger可以在 并发情况下达到原子化更新,避免使用了synchronized,而且性能非常高。由于阻塞队列的put和take操作会阻塞,为了使线程退出,特在队列 中添加了一个“标识”,算法中也叫“哨兵”,当发现这个哨兵后,写线程就退出。
当然线程池也要显式退出了。
package import java.io.F import java.io.FileF import java.util.concurrent.BlockingQ import java.util.concurrent.ExecutorS import java.util.concurrent.E import java.util.concurrent.LinkedBlockingQ import java.util.concurrent.atomic.AtomicI
public class TestBlockingQueue { static long randomTime() { return (long) (Math.random() * 1000); }
public static void main(String[] args) { // 能容纳100个文件 final BlockingQueue queue = new LinkedBlockingQueue(100); // 线程池 final ExecutorService exec = Executors.newFixedThreadPool(5); final File root = new File(“F:\\JavaLib”); // 完成标志 final File exitFile = new File(“”); // 读个数 final AtomicInteger rc = new AtomicInteger(); // 写个数 final AtomicInteger wc = new AtomicInteger(); // 读线程 Runnable read = new Runnable() { public void run() { scanFile(root); scanFile(exitFile); }
public void scanFile(File file) { if (file.isDirectory()) { File[] files = file.listFiles(new FileFilter() { public boolean accept(File pathname) { return pathname.isDirectory() || pathname.getPath().endsWith(“.java”); } }); for (File one : files) scanFile(one); } else { try { int index = rc.incrementAndGet(); System.out.println(“Read0: ” + index + ” “ + file.getPath()); queue.put(file); } catch (InterruptedException e) { } } } }; exec.submit(read); // 四个写线程 for (int index = 0; index & 4; index++) { // write thread final int NO = Runnable write = new Runnable() { String threadName = “Write” + NO; public void run() { while (true) { try { Thread.sleep(randomTime()); int index = wc.incrementAndGet(); File file = queue.take(); // 队列已经无对象 if (file == exitFile) { // 再次添加”标志”,以让其他线程正常退出 queue.put(exitFile); break; } System.out.println(threadName + “: ” + index + ” “ + file.getPath()); } catch (InterruptedException e) { } } } }; exec.submit(write); } exec.shutdown(); } }
从名字可以看出,是一个倒数计数的锁,当倒数到0时触发事件,也就是开锁,其他人就可以进入了。在一些应用场合中,需要等待某个条件达到要求后才能做后面的事情;同时当线程都完成后也会触发事件,以便进行后面的操作。
CountDownLatch最重要的方法是countDown()和await(),前者主要是倒数一次,后者是等待倒数到0,如果没有到达0,就只有阻塞等待了。
一个CountDouwnLatch实例是不能重复使用的,也就是说它是一次性的,锁一经被打开就不能再关闭使用了,如果想重复使用,请考虑使用。
下面的例子简单的说明了CountDownLatch的使用方法,模拟了100米赛跑,10名选手已经准备就绪,只等裁判一声令下。当所有人都到达终点时,比赛结束。
同样,线程池需要显式shutdown。
import java.util.concurrent.CountDownL import java.util.concurrent.ExecutorS import java.util.concurrent.E
public class TestCountDownLatch { public static void main(String[] args) throws InterruptedException { // 开始的倒数锁 final CountDownLatch begin = new CountDownLatch(1); // 结束的倒数锁 final CountDownLatch end = new CountDownLatch(10); // 十名选手 final ExecutorService exec = Executors.newFixedThreadPool(10); for(int index = 0; index & 10; index++) { final int NO = index + 1; Runnable run = new Runnable(){ public void run() { try { begin.await(); Thread.sleep((long) (Math.random() * 10000)); System.out.println(“No.” + NO + ” arrived”); } catch (InterruptedException e) { } finally { end.countDown(); } } }; exec.submit(run); } System.out.println(“Game Start”); begin.countDown(); end.await(); System.out.println(“Game Over”); exec.shutdown(); } }
运行结果: Game Start No.4 arrived No.1 arrived No.7 arrived No.9 arrived No.3 arrived No.2 arrived No.8 arrived No.10 arrived No.6 arrived No.5 arrived Game Over
有时候在实际应用中,某些操作很耗时,但又不是不可或缺的步骤。比如用网页浏览器浏览新闻时,最重要的是要显示文字 内容,至于与新闻相匹配的图片就没有那么重要的,所以此时首先保证文字信息先显示,而图片信息会后显示,但又不能不显示,由于下载图片是一个耗时的操作, 所以必须一开始就得下载。
Java的的类 就可以满足这个要求。Future的重要方法包括get()和cancel(),get()获取数据对象,如果数据没有加载,就会阻塞直到取到数据,而 cancel()是取消数据加载。另外一个get(timeout)操作,表示如果在timeout时间内没有取到就失败返回,而不再阻塞。
下面的Demo简单的说明了Future的使用方法:一个非常耗时的操作必须一开始启动,但又不能一直等待;其他重要的事情又必须做,等完成后,就可以做不重要的事情。
import java.util.concurrent.C import java.util.concurrent.ExecutionE import java.util.concurrent.ExecutorS import java.util.concurrent.E import java.util.concurrent.F
public class TestFutureTask { public static void main(String[] args)throws InterruptedException, ExecutionException { final ExecutorService exec = Executors.newFixedThreadPool(5); Callable call = new Callable() { public String call() throws Exception { Thread.sleep(1000 * 5); return “Other less important but longtime things.”; } }; Future task = exec.submit(call); // 重要的事情 Thread.sleep(1000 * 3); System.out.println(“Let’s do important things.”); // 其他不重要的事情 String obj = task.get(); System.out.println(obj); // 关闭线程池 exec.shutdown(); } }
运行结果: Let’s do important things. Other less important but longtime things.
考虑以下场景:浏览网页时,浏览器了5个线程下载网页中的图片文件,由于图片大小、网站访问速度等诸多因素的影响,完成图片下载的时间就会有很大的不同。如果先下载完成的图片就会被先显示到界面上,反之,后下载的图片就后显示。
Java的的可 以满足这种场景要求。该接口有两个重要方法:submit()和take()。submit用于提交一个runnable或者callable,一般会提 交给一个线程池处理;而take就是取出已经执行完毕runnable或者callable实例的Future对象,如果没有满足要求的,就等待了。 CompletionService还有一个对应的方法poll,该方法与take类似,只是不会等待,如果没有满足要求,就返回null对象。
import java.util.concurrent.C import java.pletionS import java.util.concurrent.ExecutionE import java.util.concurrent.ExecutorCompletionS import java.util.concurrent.ExecutorS import java.util.concurrent.E import java.util.concurrent.F
public class TestCompletionService { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService exec = Executors.newFixedThreadPool(10); CompletionService serv = new ExecutorCompletionService(exec);
for (int index = 0; index & 5; index++) { final int NO = Callable downImg = new Callable() { public String call() throws Exception { Thread.sleep((long) (Math.random() * 10000)); return “Downloaded Image ” + NO; } }; serv.submit(downImg); }
Thread.sleep(1000 * 2); System.out.println(“Show web content”); for (int index = 0; index & 5; index++) { Future task = serv.take(); String img = task.get(); System.out.println(img); } System.out.println(“End”); // 关闭线程池 exec.shutdown(); } }
运行结果: Show web content Downloaded Image 1 Downloaded Image 2 Downloaded Image 4 Downloaded Image 0 Downloaded Image 3 End
操作系统的信号量是个很重要的概念,在进程控制方面都有应用。的可以很轻松完成信号量控制,Semaphore可以控制某个资源可被同时访问的个数,acquire()获取一个许可,如果没有就等待,而release()释放一个许可。比如在Windows下可以设置共享文件的最大客户端访问个数。
Semaphore维护了当前访问的个数,提供同步机制,控制同时访问的个数。在数据结构中链表可以保存“无限”的节点,用Semaphore可以实现有限大小的链表。另外重入锁ReentrantLock也可以实现该功能,但实现上要负责些,代码也要复杂些。
下面的Demo中申明了一个只有5个许可的Semaphore,而有20个线程要访问这个资源,通过acquire()和release()获取和释放访问许可。
import java.util.concurrent.ExecutorS import java.util.concurrent.E import java.util.concurrent.S
public class TestSemaphore { public static void main(String[] args) { // 线程池 ExecutorService exec = Executors.newCachedThreadPool(); // 只能5个线程同时访问 final Semaphore semp = new Semaphore(5); // 模拟20个客户端访问 for (int index = 0; index & 20; index++) { final int NO = Runnable run = new Runnable() { public void run() { try { // 获取许可 semp.acquire(); System.out.println(“Accessing: ” + NO); Thread.sleep((long) (Math.random() * 10000)); // 访问完后,释放 semp.release(); } catch (InterruptedException e) { } } }; exec.execute(run); } // 退出线程池 exec.shutdown(); } }
运行结果: Accessing: 0 Accessing: 1 Accessing: 2 Accessing: 3 Accessing: 4 Accessing: 5 Accessing: 6 Accessing: 7 Accessing: 8 Accessing: 9 Accessing: 10 Accessing: 11 Accessing: 12 Accessing: 13 Accessing: 14 Accessing: 15 Accessing: 16 Accessing: 17 Accessing: 18 Accessing: 19
精品视频课程推荐
WebLogic基础知识:WebLogic基本概念、正确安装WebLogic、建域、应用部署于JDBC选择、对WebLogic的监控和日志查看、集群的高可用性;课程目标:彻底掌握WebLogic的基本概念,在理解基本概念的基础上做到正确的安装WebLogic,根据不同的需求创建域,合理选择应用部署和JDBC配置。熟练掌握WebLogic的console监控,了解各种性能和运行指标,以及对监控结果的分析,运用集群的高可用性,对集群架设。
内容概述:Shiro是目前最热门、最易用、功能超强大的Java权限管理框架,强烈推荐,每个项目都必备的权限管理技术!通过本课程,你将从零开始直到彻底掌握Shiro的相关开发知识,达到可以进行实际项目开发的能力。包括:权限管理基础、Shiro入门、配置、身份认证、授权、Realms、Session管理、和Spring的集成、Web、Cache等众多开发细节技术
技术要点:源码级分析Shiro的授权过程、自定义开发Realm、多个Realms的开发配置、自定义开发AuthenticationStrategy、自定义开发自定义SessionDAO、和Struts2+Spring3的集成(包括修正struts2的bug)、Shiro和SpringMVC+Spring3的集成、包装使用其他的Cache框架、缓存数据同步更新的解决方案等等实际开发中常用的内容
系统、完整的学习Spring Web MVC开发的知识。包括:Spring Web MVC入门;理解DispatcherServlet;注解式控制器开发详解;数据类型转换;数据格式化;数据验证; 拦截器;对Ajax的支持;文件上传下载;表单标签等内容;最后以一个综合的CRUD带翻页的应用示例来综合所学的知识
深入浅出的讲解JavaBen的写法、JavaBean的用法、JavaBean的实现机制、JavaBean对应翻译的代码理解。
从零到精通jBPM的开发知识;理解工作流的理论、掌握自行开发工作流的思路、系统学习使用jBPM来实现工作流应用、掌握jBPM和Web项目的结合、掌握一些实际开发中典型的业务实现(会签、委托等)
浏览(6702)|(0)
&&交流分类:|笔记分类:
版权所有 Copyright(C) 私塾在线学习网}

我要回帖

更多关于 countdownlatch 超时 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信