目录
JUC
java.util.concurrent 下的类就叫 JUC 类,JUC 下典型的类有:
ReentrantLock
Semaphore
CountDownLatch
CyclicBarrier
ReentrantLock:可重入锁
Semaphore:信号量(可以实现限流)
-acquire:获得令牌
-release:发布令牌
import java.time.LocalDateTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* 信号量(可以实现限流)
*/
public class SemaphoreDemo1 {
public static void main(String[] args) {
//创建线程池
ExecutorService service= Executors.newFixedThreadPool(5);
//创建信号量
Semaphore semaphore=new Semaphore(2);
//统一任务的定义
Runnable runnable=new Runnable() {
@Override
public void run() {
Thread currThread=Thread.currentThread();//得到执行此任务的线程
System.out.println("进入线程:"+currThread.getName());
try {
//获取令牌
semaphore.acquire();//如果没有可用令牌,线程会阻塞在当前位置
System.out.println(currThread.getName()+":得到了令牌|Time"+
LocalDateTime.now());
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println(currThread.getName()+":释放令牌|Time"+
LocalDateTime.now());
//释放令牌
semaphore.release();
}
}
};
//定义新线程执行任务
service.submit(runnable);
//定义新线程执行任务
service.submit(runnable);
//定义新线程执行任务
service.submit(runnable);
//定义新线程执行任务
service.submit(runnable);
//定义新线程执行任务
service.submit(runnable);
}
}
CountDownLatch:计数器:判断线程池的任务是否已经全部执行完
-countDown:计数器-1
-await:阻塞等待,所有的任务全部执行完(等待CountDownLatch=0后继续执行后面的代码)
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* 计数器使用
*/
public class CountDownLatchDemo1 {
public static void main(String[] args) throws InterruptedException {
//创建计数器
CountDownLatch countDownLatch = new CountDownLatch(5);
//创建新线程执行任务
for (int i = 1; i < 6; i++) {
new Thread(() -> {
Thread currThread = Thread.currentThread();
System.out.println(currThread.getName() + "开始起跑");
try {
//跑步所用时间
int runTime = (1 + new Random().nextInt(5));
TimeUnit.SECONDS.sleep(runTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(currThread.getName() + ":到达终点,用时:");
countDownLatch.countDown();
}, "选手-" + i).start();
}
countDownLatch.await();
System.out.println("宣布比赛结果");
}
}
CyclicBarrier:循环屏障(线程分组的阻塞)
-await:计数器-1,判断当前计数器是否为0,如果是0,冲破栅栏执行之后的代码;否则阻塞等待,直到栅栏被冲坡。
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 循环屏障
*/
public class CyclicBarrierDemo1 {
public static void main(String[] args) {
//循环屏障
CyclicBarrier cyclicBarrier=new CyclicBarrier(5, new Runnable() {
@Override
public void run() {
System.out.println("计数器为0了");
}
});
//创建线程池
ExecutorService service=Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
int finalI = i;
service.submit(()->{
Thread currThread=Thread.currentThread();
System.out.println("执行线程:"+currThread.getName());
try {
Thread.sleep(500* finalI);
cyclicBarrier.await();//执行阻塞等待(计数器-1,阻塞等待,直到循环屏障的计数器为0的时候,在执行后面的代码)
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("执行线程完成:"+currThread.getName());
});
}
}
}
非线程安全容器
Java 标准库中很多都是线程不安全的. 这些类可能会涉及到多线程修改共享数据, 又没有任何加锁措施.
ArrayList
LinkedList
HashMap
TreeMap
HashSet
TreeSet
StringBuilder
线程安全容器
Vector (不推荐使用)
Hashtable (不推荐使用,性能低)
ConcurrentHashMap
StringBuffer
HashMap知识点
1.底层数据结构实现
2.负载因子(扩充因子作用)
3.哈希冲突是如何解决的
4.是否是线程安全的?为什么?
首先 HashMap 是线程不安全的,其主要体现:
在 jdk 1.7 中,在多线程环境下,扩容时因为采用头插法,会造成死循环和数据覆盖。
在 jdk 1.8 中,在多线程环境下,会发生数据覆盖的情况。
5.如何解决线程安全问题?加锁/ConcurrentHashMap
6.ConcurrentHashMap如何实现线程安全?