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);}@Overridepublic 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;}@Overridepublic 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);@Overridepublic 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: 数组结构,线程安全的(效率低)