等待多线程完成
主线程等待所有线程完成工作
实现
thread.join()方法
private static void join() throws InterruptedException {
int length = 100;
Long t1 = System.nanoTime();
List<Integer> results = new ArrayList<>();
for (int index = 0; index < length; index++) {
final int threadIndex = index;
Thread thread = new Thread(() -> {
System.out.println("start thread - " + threadIndex);
Double random = -1.0;
try {
Thread.sleep(1 * 1000);
random = (100 * Math.random());
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("stop thread - " + threadIndex + " random = " + random.intValue());
results.add(random.intValue());
});
thread.start();
thread.join();
}
System.out.println("跑完了...");
Long t2 = System.nanoTime();
System.out.println(results);
System.out.println("time = " + (t2 - t1));
}
原理
join 用于让当前执行线程等待join线程执行结束。
其实现原理是不停检查join线程是否存活,如果join线程存活则让当前线程永远等待。
其中,wait(0)表示永远等待下去
while(isAlive){
wait(0);
}
直到join线程中止后,线程的this.notifyAll()方法会被调用,调用notifyAll()是在JVM实现的,所以在jdk里看不到
CountDownLatch
private static void countDownLatch() throws InterruptedException {
int length = 100;
CountDownLatch latch = new CountDownLatch(length);
Long t1 = System.nanoTime();
List<Integer> results = new ArrayList<>();
for (int index = 0; index < length; index++) {
final int threadIndex = index;
Thread thread = new Thread(() -> {
System.out.println("start thread - " + threadIndex);
Double random = -1.0;
try {
Thread.sleep(1 * 1000);
random = (100 * Math.random());
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("stop thread - " + threadIndex + " random = " + random.intValue());
results.add(random.intValue());
latch.countDown();
});
thread.start();
}
// 注意:CountDownLatch要加上这段才生效,原因见下面文字描述
latch.await();
System.out.println("跑完了...");
Long t2 = System.nanoTime();
System.out.println(results);
System.out.println("time = " + (t2 - t1));
}
原理
CountDownLatch的构造函数接受一个int类型的参数作为计数器,如果你想等待N个节点(N个Thread 如上述示例 ),这里就传入N
CountDownLatch.countDown()
调用CountDownLatch.countDown() ,N就会减1
CountDownLatch.wait()
CountDownLatch.wait()会阻塞当前线程,直到N变成零
当某个线程处理的特别慢时,如果不需要主线程一直等待下去,可以使用另外一个重载的wait(long time,TimeUnit unit),这个方法等待指定时间后就不再阻塞线程了
join也有类似的方法
结论
join()与CountDownLatch都能实现 主线程等待所有线程完成工作 的功能,但明显 CountDownLatch 效率更高
控制并发线程数
Semaphore
public class StudySemaphore {
public static void main(String[] args) {
int THREAD_COUNT = 30;
ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_COUNT);
Semaphore semaphore = new Semaphore(5);
for (int index = 0; index < THREAD_COUNT; index++) {
threadPool.execute(() -> {
try {
semaphore.acquire();
Thread.sleep(1 * 1000);
System.out.println(String.format("%s do with something end - 当前等待的线程数:%s", Thread.currentThread().getName(), semaphore.getQueueLength()));
semaphore.release();
} catch (InterruptedException e) {
//
}
});
}
threadPool.shutdown();
}
}
原理
Semaphore 的构造方法接受一个int类型的参数,表示可用的许可证数量
new Semaphore(5) 表示允许5个线程获取许可证,也就是最大并发数5
Semaphore.acquire()
Semaphore.acquire() 方法获取一个许可证
Semaphore.release()
使用完后调用 Semaphore.release() 方法归还许可证
Semaphore.tryAcquire()
也可以使用 tryAcquire() 尝试获取许可证
学习《java并发编程的艺术》