1.Hashtable和ConcurrentHashMap
Hashtable:哈希表结构(数组+链表),线程安全的(同步代码块,效率低)
ConcurrentHashMap:
jdk7:采用Segment数组[不会扩容] + HashEntry[二次哈希计算存入的位置,可扩容],线程安全(synchronized)
jdk8:哈希表结构(数组+链表+红黑树),线程安全的(synchronized+CAS算法,效率高)
【注:使用线程不安全的类可能会出现赋值为null的情况】
public class Demo3 {
public static void main(String[] args) throws InterruptedException {
//Hashtable<String, String> hsTable = new Hashtable<>();
ConcurrentHashMap<String, String> concurrentHashMap = new ConcurrentHashMap<>();
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 25; i++) {
concurrentHashMap.put(i + "", i + "");
}
});
Thread thread2 = new Thread(() -> {
for (int i = 25; i < 51; i++) {
concurrentHashMap.put(i + "", i + "");
}
});
thread1.start();
thread2.start();
System.out.println("--------------------");
//为了两条线程的数据都添加完毕
Thread.sleep(1000);
//打印集合的所有值
for (int i = 0; i < 51; i++) {
System.out.println(concurrentHashMap.get(i + ""));
}
}
}
打印结果:
--------------------------------------------------------------------------------------
0
......
49
50
2.CountDownLatch
孩子吃完饺子,妈妈收拾碗筷【使用场景:当需要某一个线程在其他线程执行完毕之后才执行】
原理:创建CountDownLatch的对象,参数为等待线程的数量, 并定义了一个计数器,初始值为参数的值
//CountDownLatch 并发工具类
public class Demo {
public static void main(String[] args) {
//创建CountDownLatch的对象,参数为等待线程的数量
//并定义了一个计数器,初始值为参数的值【参数为多少则几条线程结束后才执行】
CountDownLatch countDownLatch = new CountDownLatch(1);
//countDownLatch传递到4个线程时,它们则共用一个计数器
MotherThread motherThread = new MotherThread(countDownLatch,"妈妈---");
ChildThread1 childThread1 = new ChildThread1(countDownLatch,"小刚---");
//ChildThread2 childThread2 = new ChildThread2(countDownLatch,"小明---");
//ChildThread3 childThread3 = new ChildThread3(countDownLatch,"小红---");
motherThread.start();
childThread1.start();
//childThread2.start();
//childThread3.start();
}
}
//ChildThread1 孩子1线程,同理其他孩子线程与之一致,可复制添加
public class ChildThread1 extends Thread {
private CountDownLatch countDownLatch;
public ChildThread1(CountDownLatch countDownLatch, String s) {
this.countDownLatch = countDownLatch;
this.setName(s);
}
@Override
public void run() {
//1.吃饺子
for (int i = 1; i <= 3; i++) {
System.out.println(Thread.currentThread().getName() + "在吃" + i + "个饺子");
}
//2.吃完说一声
//每一次countDown方法后,count--;
countDownLatch.countDown();
}
}
//妈妈线程
public class MotherThread extends Thread{
private CountDownLatch countDownLatch;
public MotherThread(CountDownLatch countDownLatch, String s) {
this.countDownLatch=countDownLatch;
}
@Override
public void run() {
try {
//1.等待
//当计数器变为0时,会自动唤醒等待的线程
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
//2.收拾碗筷
System.out.println("妈妈正在收拾碗筷");
}
}
打印结果:
--------------------------------------------------------------------------------------
小刚---在吃1个饺子
小刚---在吃2个饺子
小刚---在吃3个饺子
妈妈正在收拾碗筷
3.Semaphore管理员对象
用来控制正在执行的线程数量
//Semaphore管理员对象【用来控制正在执行的线程数量】
public class Demo1 {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
//开启100条线程
for (int i = 0; i < 4; i++) {
new Thread(myRunnable).start();
}
}
}
//具体实现类
public class MyRunnable implements Runnable {
//1.创建Semaphore对象,参数为通行证数量
Semaphore semaphore =new Semaphore(2);
@Override
public void run() {
try {
//2.获得通行证
semaphore.acquire();
//3.开始行驶
System.out.println("获得了通行证开始通行");
//4.归还通行证
System.out.println("归还通信证");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
打印结果:
--------------------------------------------------------------------------------------
获得了通行证开始通行
归还通信证
获得了通行证开始通行
归还通信证
获得了通行证开始通行
归还通信证
获得了通行证开始通行
归还通信证
4.其他线程安全类
StringBuilder和StringBuffer
StringBuilder: 线程不安全的(效率高)
StringBuffer: 线程安全的(效率低)
安全的原因是因为其内部方法都有锁
ArrayList和Vector
ArrayList: 数组结构,线程不安全(效率高)
Vector: 数组结构,线程安全的(效率低)