Hashtable
出现的原因:在集合类中HashMap是比较常用的集合对象,但是HashMap是线程不安全的(多线程环境下可能会存在问题),为了保证数据的安全性,可以使用Hashtable,但是Hashtable的效率底下,因为Hashtable底层代码是同步方法,当锁的时候是锁一整张table
示例代码
public class HashMapAndTable {
public static void main(String[] args) throws InterruptedException {
Hashtable<String,String> hashtable = new Hashtable<>();
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 25; i++) {
hashtable.put(i + "",i + "");
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 51; i++) {
hashtable.put(i + "",i + "");
}
});
thread1.start();
thread2.start();
Thread.sleep(1000);
for (int i = 0; i < 51; i++) {
System.out.println(hashtable.get(i + ""));
}
}
}
ConcurrentHashMap
出现原因:在集合类中HashMap是比较常用的集合对象,但是HashMap是线程不安全的(多线程环境下可能会存在问题)。为了保证数据的安全性我们可以使用Hashtable,但是Hashtable的效率低下。基于以上两个原因我们可以使用JDK1.5以后所提供的ConcurrentHashMap。
体系结构
代码示例
public class CurrentHashMap_ {
public static void main(String[] args) throws InterruptedException {
ConcurrentHashMap<String,String> concurrentHashMap = new ConcurrentHashMap<>();
Thread thread_01 = new Thread(() -> {
for (int i = 0; i < 25; i++) {
concurrentHashMap.put(i + "",i + "");
}
});
Thread thread_02 = new Thread(() -> {
for (int i = 0; i < 51; i++) {
concurrentHashMap.put(i + "",i + "");
}
});
thread_01.start();
thread_02.start();
Thread.sleep(1000);
for (int i = 0; i < 51; i++) {
System.out.println(concurrentHashMap.get(i + ""));
}
}
}
总结:
1、HashMap是线程不安全的。多线程环境下会有数据安全问题
2、Hashtable是线程安全的,但是会将整张表锁起来,效率低下
3、ConcurrentHashMap也是线程安全的,效率较高。在 JDK7 和 JDK8中,底层原理不一样
ConcurrentHashMap 1,7原理
1、默认创建一个长度16,步长为0.75的大数组(这个大数组一旦创建无法扩容)
2、还会创建一个长度为2的小数组,把地址值赋值给0索引处,其他索引位置的元素都是null
ConcurrentHashMap 1,8原理
总结:
1、如果使用空参构造创建ConcurrentHashMap对象,则什么事都不做,在第一次添加元素的时候创建哈希表
2、计算当前元素应存入的索引
3、如果该索引位置为null,则利用CAS算法,将本节点添加到数组中
4、如果该索引位置不为null,则利用volatile关键字获得当前位置最新的节点地址,挂在他下面,变成一个链表
5、当链表的长度大于等于8时,自动转换成红黑树6,以链表或者红黑树节点为锁对象,配合悲观锁保证多线程操作集合时数据的安全性(只锁当前)
CountDownLatch
使用场景:让某一条线程等待其他线程执行完毕之后再执行
方法 | 解释 |
---|---|
public CountDownLatch(int count) | 参数传递线程数,表示等待线程数量 |
public void await() | 让线程等待 |
public void countDown() | 当前线程执行完毕 |
示例代码
public class CountDownLatch__ {
public static void main(String[] args) {
CountDownLatch count = new CountDownLatch(3);
Thread thread = new Thread(() -> {
for (int i = 0; i < 10; i++) {
count.countDown();
count.countDown();
count.countDown();
try {
count.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("hello");
}
});
thread.start();
}
}
Semaphore
使用场景:可以控制访问特定资源的线程数量public class Semaphore__ {
public static void main(String[] args) {
//可以控制访问特定资源的线程数量
Semaphore semaphore = new Semaphore(2);
Thread thread = new Thread(() -> {
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 100; i++) {
System.out.println("hello");
}
semaphore.release();
});
thread.start();
}
}