ConcurrentHashMap
1、在jdk中,我们常用的map集合是 HashTable 和 HashMap 这两个,其中HashTable是线程安全的,即里面的每一个方法都是线程同步的方法,使用了synchronized关键字修饰,而HashMap是线程不安全的。
2、虽然HashTable是线程安全的,但是效率很低,所以在jdk1.5之后,在并发包中就增加了一个线程安全,效率也高的map集合,叫 ConcurrentHashMap
3、ConcurrentHashMap 是接口ConcurrentMap的实现类,它还有一个实现类,是ConcurrentskipListMap (支持并发排序功能。弥补ConcurrentHas hMa p)
4、ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个
小的HashTable,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并
发进行。把一个整体分成了16个段(Segment.也就是最高支持16个线程的并发修改操作。
这也是在重线程场景时减小锁的粒度从而降低锁竞争的一种方案。并且代码中大多共享变
量使用volatile关键字声明,目的是第一时间获取修改的内容,性能非常好。(这个也就是分段锁)
CountDownLatch
CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。
比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。
public class Test002 {
public static void main(String[] args) throws InterruptedException {
System.out.println("等待子线程执行完毕...");
CountDownLatch countDownLatch = new CountDownLatch(2);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("子线程," + Thread.currentThread().getName() + "开始执行...");
countDownLatch.countDown();// 每次减去1
System.out.println("子线程," + Thread.currentThread().getName() + "结束执行...");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("子线程," + Thread.currentThread().getName() + "开始执行...");
//countDownLatch技术器减一
countDownLatch.countDown();
System.out.println("子线程," + Thread.currentThread().getName() + "结束执行...");
}
}).start();
// 调用当前方法主线程阻塞 直到countDown结果为0, 阻塞变为运行状态
countDownLatch.await();
System.out.println("两个子线程执行完毕....");
System.out.println("继续主线程执行..");
}
}
分析:上面的代码中,定义了一个全局的countDownLatch技术器,让主线程和两个子线程都可以访问这个countDownLatch技术器,每一个子线程运行完,countDownLatch技术器就减一,而主线程调用了countDownLatch.await()方法,一直处于阻塞状态,知道两个线程都运行完,countDownLatch技术器变成0,主线程才继续执行
注意:上面的代码中,如果countDownLatch技术器初始值为 1 ,而有两个线程,此时也不会报错,只是在一个线程执行完成后,countDownLatch变成0,主线程就会和另一个子线程竞争cpu资源