目录
一·线程池
1、为什么使用线程池
2、使用线程池
拒绝策略
AbortPolicy 丢弃任务并抛出RejectedExecutionException异常(默认)
CallerRunsPolicy 由调用线程处理该任务
DiscardOldestPolicy 丢弃队列最前面的任务然后重新尝试执行该任务,重复此过程
DiscardPolicy 丢弃被拒绝的任务
3、jdk已提供的线程池
①FixedThreadPool
特点:固定数量线程池
ExecutorService executorService = Executors.newFixedThreadPool(4);
源码:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
核心线程数已最大线程数一致,即:线程池初始化核心线程后就不会再创建新线程了。
队列为链表阻塞队列,无界队列,当请求一多可能造成OOM。
②CachedThreadPool
特点:可缓存的线程池、具有自动回收多余线程的功能
ExecutorService executorService = Executors.newCachedThreadPool();
源码:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
当有请求过来时就直接新建线程去执行,当线程执行完毕,存活为60s后开始回收线程。核心线程数为0,最大线程数为Integer的最大值,队列为直接交接队列即不会存储数据的。
③ScheduledThreadPool
特点:支持定时及周期性执行任务
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(10);
// threadPool.schedule(new Task(), 5, TimeUnit.SECONDS);
threadPool.scheduleAtFixedRate(new Task(), 1, 3, TimeUnit.SECONDS);
④比较
二·ThreadLocal
2、使用场景
![](https://i-blog.csdnimg.cn/blog_migrate/b0226ba4eefe8dc8b8407580d38f7fef.png)
①每个线程独享变量
public class ThreadLocalNormalUsage05 {
public static ExecutorService threadPool = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
int finalI = i;
threadPool.submit(() -> {
String date = new ThreadLocalNormalUsage05().date(finalI);
System.out.println(date);
});
}
threadPool.shutdown();
}
public String date(int seconds) {
//参数的单位是毫秒,从1970.1.1 00:00:00 GMT计时
Date date = new Date(1000 * seconds);
// SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat dateFormat = ThreadSafeFormatter.dateFormatThreadLocal .get();
return dateFormat.format(date);
}
}
class ThreadSafeFormatter {
public static ThreadLocal<SimpleDateFormat> dateFormatThreadLocal = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
};
}
②避免传参麻烦每个线程保存全局变量
public class ThreadLocalNormalUsage06 {
public static void main(String[] args) {
new Service1().process("");
}
}
class Service1 {
public void process(String name) {
User user = new User("超哥");
UserContextHolder.holder.set(user);
new Service2().process();
}
}
class Service2 {
public void process() {
User user = UserContextHolder.holder.get();
ThreadSafeFormatter.dateFormatThreadLocal.get();
System.out.println("Service2拿到用户名:" + user.name);
new Service3().process();
}
}
class Service3 {
public void process() {
User user = UserContextHolder.holder.get();
System.out.println("Service3拿到用户名:" + user.name);
UserContextHolder.holder.remove();
}
}
class UserContextHolder {
public static ThreadLocal<User> holder = new ThreadLocal<>();
}
class User {
String name;
public User(String name) {
this.name = name;
}
}
2、用法总结
![](https://i-blog.csdnimg.cn/blog_migrate/1b77470c5d7733603f330421c2746c2c.png)
3、好处
![](https://i-blog.csdnimg.cn/blog_migrate/51a6e9085252a9d391fe538e59e7421a.png)
4、原理
①ThreadLocal
②TheadLocalMap
5、使用注意点
①内存泄漏
②避免
三·锁
1、Lock
①简介
②使用
2、锁的分类
①乐观锁和悲观锁
乐观锁:非互斥同步锁
悲观锁:互斥同步锁
②可重入锁
无需释放锁即可再次获得锁synchornized也是
③公平锁与非公平锁
④共享锁和排它锁
JAVA中的读写锁
private static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
private static ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
private static ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();
应用
private static void read() {
readLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "得到了读锁,正在读取");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName() + "释放读锁");
readLock.unlock();
}
}
private static void write() {
writeLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "得到了写锁,正在写入");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName() + "释放写锁");
writeLock.unlock();
}
}
写锁线程造成饥饿
ReentrantReadWriteLock的实现:
源码分析
公平锁
都不能插队,如果队列中你就需要等待
非公平锁
⑤锁的升级以及降级
可以降及不可以升级,即可以由写锁降为读锁并释放写锁。不能由读锁升级为写锁,因为能多读或一写升级容易造成死锁。
写锁降级为读锁
private static void writeDowngrading() {
writeLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "得到了写锁,正在写入");
Thread.sleep(1000);
readLock.lock();
System.out.println("在不释放写锁的情况下,直接获取读锁,成功降级");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readLock.unlock();
System.out.println(Thread.currentThread().getName() + "释放写锁");
writeLock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
System.out.println("先演示降级是可以的");
Thread thread1 = new Thread(() -> writeDowngrading(), "Thread1");
thread1.start();
}
读锁升级为写锁
private static void readUpgrading() {
readLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "得到了读锁,正在读取");
Thread.sleep(1000);
System.out.println("升级会带来阻塞");
writeLock.lock();
System.out.println(Thread.currentThread().getName() + "获取到了写锁,升级成功");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName() + "释放读锁");
readLock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
System.out.println("演示升级是不行的");
Thread thread2 = new Thread(() -> readUpgrading(), "Thread2");
thread2.start();
}
⑥自旋锁和阻塞锁
private final AtomicReference<Thread> sign = new AtomicReference<>();
public void lock() {
Thread current = Thread.currentThread();
while (!sign.compareAndSet(null, current)) {
System.out.println("自旋获取失败,再次尝试");
}
}
public void unlock() {
Thread current = Thread.currentThread();
sign.compareAndSet(current, null);
}
public static void main(String[] args) {
SpinLock spinLock = new SpinLock();
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "开始尝试获取自旋锁");
spinLock.lock();
System.out.println(Thread.currentThread().getName() + "获取到了自旋锁");
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
spinLock.unlock();
System.out.println(Thread.currentThread().getName() + "释放了自旋锁");
}
}
};
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
thread1.start();
thread2.start();
}
⑥可中断锁
private Lock lock = new ReentrantLock();
public static void main(String[] args) {
LockInterruptibly lockInterruptibly = new LockInterruptibly();
Thread thread0 = new Thread(lockInterruptibly);
Thread thread1 = new Thread(lockInterruptibly);
thread0.start();
thread1.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread1.interrupt();
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "尝试获取锁");
try {
lock.lockInterruptibly();
try {
System.out.println(Thread.currentThread().getName() + "获取到了锁");
Thread.sleep(5000);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + "睡眠期间被中断了");
} finally {
lock.unlock();
System.out.println(Thread.currentThread().getName() + "释放了锁");
}
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + "获得锁期间被中断了");
}
}
四·atomic
①介绍
②AtomicInteger
演示原子类与非原子类
private static final AtomicInteger atomicInteger = new AtomicInteger();
public void incrementAtomic() {
atomicInteger.getAndIncrement();
}
private static volatile int basicCount = 0;
public void incrementBasic() {
basicCount++;
}
public static void main(String[] args) throws InterruptedException {
AtomicIntegerDemo1 r = new AtomicIntegerDemo1();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("原子类的结果:" + atomicInteger.get());
System.out.println("普通变量的结果:" + basicCount);
}
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
incrementAtomic();
incrementBasic();
}
}
在非原子方法上加锁也可变成线程安全的
③AtomicArray
public class AtomicArrayDemo {
public static void main(String[] args) throws InterruptedException {
AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(1000);
Incrementer incrementer = new Incrementer(atomicIntegerArray);
Decrementer decrementer = new Decrementer(atomicIntegerArray);
Thread[] threadsIncrementer = new Thread[100];
Thread[] threadsDecrementer = new Thread[100];
for (int i = 0; i < 100; i++) {
threadsDecrementer[i] = new Thread(decrementer);
threadsIncrementer[i] = new Thread(incrementer);
threadsDecrementer[i].start();
threadsIncrementer[i].start();
}
// Thread.sleep(10000);
for (int i = 0; i < 100; i++) {
try {
threadsDecrementer[i].join();
threadsIncrementer[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 0; i < atomicIntegerArray.length(); i++) {
if (atomicIntegerArray.get(i)!=0) {
System.out.println("发现了错误"+i);
}
System.out.println(atomicIntegerArray.get(i));
}
System.out.println("运行结束");
}
}
class Decrementer implements Runnable {
private AtomicIntegerArray array;
public Decrementer(AtomicIntegerArray array) {
this.array = array;
}
@Override
public void run() {
for (int i = 0; i < array.length(); i++) {
array.getAndDecrement(i);
}
}
}
class Incrementer implements Runnable {
private AtomicIntegerArray array;
public Incrementer(AtomicIntegerArray array) {
this.array = array;
}
@Override
public void run() {
for (int i = 0; i < array.length(); i++) {
array.getAndIncrement(i);
}
}
}
④Atomic*Reference
public class SpinLock {
private final AtomicReference<Thread> sign = new AtomicReference<>();
public void lock() {
Thread current = Thread.currentThread();
while (!sign.compareAndSet(null, current)) {
System.out.println("自旋获取失败,再次尝试");
}
}
public void unlock() {
Thread current = Thread.currentThread();
sign.compareAndSet(current, null);
}
public static void main(String[] args) {
SpinLock spinLock = new SpinLock();
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "开始尝试获取自旋锁");
spinLock.lock();
System.out.println(Thread.currentThread().getName() + "获取到了自旋锁");
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
spinLock.unlock();
System.out.println(Thread.currentThread().getName() + "释放了自旋锁");
}
}
};
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
thread1.start();
thread2.start();
}
}
⑤普通变量升级为原子功能变量
public class AtomicIntegerFieldUpdaterDemo implements Runnable{
static Candidate tom;
static Candidate peter;
public static AtomicIntegerFieldUpdater<Candidate> scoreUpdater = AtomicIntegerFieldUpdater
.newUpdater(Candidate.class, "score");
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
peter.score++;
scoreUpdater.getAndIncrement(tom);
}
}
public static class Candidate {
volatile int score;
}
public static void main(String[] args) throws InterruptedException {
tom=new Candidate();
peter=new Candidate();
AtomicIntegerFieldUpdaterDemo r = new AtomicIntegerFieldUpdaterDemo();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("普通变量:"+peter.score);
System.out.println("升级后的结果"+ tom.score);
}
}
⑥累加器
比较
AtomicLong
public class AtomicLongDemo {
public static void main(String[] args) throws InterruptedException {
AtomicLong counter = new AtomicLong(0);
ExecutorService service = Executors.newFixedThreadPool(20);
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
service.submit(new Task(counter));
}
service.shutdown();
while (!service.isTerminated()) {
}
long end = System.currentTimeMillis();
System.out.println(counter.get());
System.out.println("AtomicLong耗时:" + (end - start));
}
private static class Task implements Runnable {
private AtomicLong counter;
public Task(AtomicLong counter) {
this.counter = counter;
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
counter.incrementAndGet();
}
}
}
}
LongAdder
public class LongAdderDemo {
public static void main(String[] args) throws InterruptedException {
LongAdder counter = new LongAdder();
ExecutorService service = Executors.newFixedThreadPool(20);
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
service.submit(new Task(counter));
}
service.shutdown();
while (!service.isTerminated()) {
}
long end = System.currentTimeMillis();
System.out.println(counter.sum());
System.out.println("LongAdder耗时:" + (end - start));
}
private static class Task implements Runnable {
private LongAdder counter;
public Task(LongAdder counter) {
this.counter = counter;
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
counter.increment();
}
}
}
}
五·CAS
①简介及原理
public class TwoThreadsCompetition implements Runnable {
private volatile int value;
public synchronized int compareAndSwap(int expectedValue, int newValue) {
int oldValue = value;
if (oldValue == expectedValue) {
value = newValue;
}
return oldValue;
}
public static void main(String[] args) throws InterruptedException {
TwoThreadsCompetition r = new TwoThreadsCompetition();
r.value = 0;
Thread t1 = new Thread(r,"Thread 1");
Thread t2 = new Thread(r,"Thread 2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(r.value);
}
@Override
public void run() {
compareAndSwap(0, 1);
}
}
②缺点
Java解决ABA问题AtomicStampedReference
一个初始值及一个时间戳
CAS
.
不仅会比较值的相等还会比较设置值的时间戳是否相等。
mysql实现乐观锁时也会新增一个版本号来解决ABA的问题。
六·final
①不变性
②作用
③栈封闭技术
public class StackConfinement implements Runnable {
int index = 0;
public void inThread() {
int neverGoOut = 0;
synchronized (this) {
for (int i = 0; i < 10000; i++) {
neverGoOut++;
}
}
System.out.println(Thread.currentThread().getName()+":栈内保护的数字是线程安全的:" + neverGoOut);
}
@Override
public void run() {
for (int i = 0; i < 20000000; i++) {
index++;
}
inThread();
}
public static void main(String[] args) throws InterruptedException {
StackConfinement r1 = new StackConfinement();
Thread thread1 = new Thread(r1,"t1");
Thread thread2 = new Thread(r1,"t2");
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("共享变量的数字是现成不安全的:"+r1.index);
}
}
public class StackConfinement implements Runnable {
int index = 0;
public void inThread() {
int neverGoOut = 0;
synchronized (this) {
for (int i = 0; i < 10000; i++) {
neverGoOut++;
}
}
System.out.println(Thread.currentThread().getName()+":栈内保护的数字是线程安全的:" + neverGoOut);
}
@Override
public void run() {
for (int i = 0; i < 20000000; i++) {
index++;
}
inThread();
}
public static void main(String[] args) throws InterruptedException {
StackConfinement r1 = new StackConfinement();
Thread thread1 = new Thread(r1,"t1");
Thread thread2 = new Thread(r1,"t2");
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("共享变量的数字是现成不安全的:"+r1.index);
}
}
七·并发集合
①并发容器概览
②集合历史
1、Vectory线程安全的List但是并发时效率不行
Synchornized关键字修饰在方法上
2、Hashtable线程安全的Map但是并发时效率不行
同样Synchornized关键字修饰在方法上
3、ArrayList线程不安全的
但是可以通过Collections.synchornizedList(new ArrayList<E>())变为线程安全的
public class SynList implements Runnable{
static List <Integer> unSafe = new ArrayList<>();
static List<Integer> safeList = Collections.synchronizedList(new ArrayList<>());
@Override
public void run() {
for (int i = 0; i < 200000; i++) {
unSafe.add(i);
safeList.add(i);
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new SynList());
Thread thread2 = new Thread(new SynList());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("现成安全的List:"+safeList.size());
System.out.println("现成不安全的List:"+unSafe.size());
}
}
源码追踪:
ArrayList继承了RandomAccess
锁住的是代码块,所以是线程安全的,但是效率也不比Vector好到哪里去
4、HashMap线程不安全的
但是可以通过Collections.synchornizedMap(new HashMap<>())实现线程安全
public class SynMap implements Runnable{
static Map<String, Integer> unSafe = new HashMap<>();
static Map<String, Integer> safeMap = Collections.synchronizedMap(new HashMap<>());
@Override
public void run() {
for (int i = 0; i < 200000; i++) {
unSafe.put(i+"",i);
safeMap.put(i+"",i);
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new SynMap());
Thread thread2 = new Thread(new SynMap());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("现成安全的Map:"+safeMap.size());
System.out.println("现成不安全的Map:"+unSafe.size());
}
源码追踪:
同样锁住的是代码块,所以是现成安全的,但是效率也不比HashTabel好到哪里去
CopyOnWriteArrayList使用读多写少的场景,在修改频繁的场景下效率没有Collections.synchornizedList(new ArrayList())效率高。
③Map
1、jdk1.7 hashMap死循环造成CPU100%
在多个线程同时扩容的时候会造成链表的死循环
https://coolshell.cn/articles/9606.html
2、hashMap 1.7和1.8结构图和特点
Jdk1.7拉链法
Jdk1.8拉链法升级为红黑树
当拉链法到达一定阈值时升级为红黑树
左边的值会比父节点小,右边的值会比父节点大
3、ConcurrentHashMap
JDK1.7
JDK1.8
1.7到1.8的升级
数据结构:
1.7采用一个一个的segment分段来实现具有并发能力但是只有16,1.8采用链表+红黑树,每个node都是独立的支持更高的并发。
Hash碰撞:
1.7采用拉链法,1.8先采用拉链后面达到阈值时转为红黑树提高了查找效率
保证并发安全:
1.7采用分段锁采用segment(集成了rentrantlock),1.8采用cas+synchornized实现
查询复杂度:
1.7采用链表查询复杂度是O(n),1.8采用红黑树查询复杂度是O(logn)
为什么要在链表长度为8的时候转为红黑树:
默认不是红黑树节点默认是链表节点,因为链表节点占的内存更少
想要达到冲突为8,正常情况下为千万分之一的概率
④CopyOnWriteArrayList
ArryList使用迭代器修改、新增、删除数据再第二次进入循环执行iterator.next会报错
public class CopyOnWriteArrayListDemo1 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
System.out.println(next);
System.out.println("list is" + list);
if (next.equals("1")) {
list.add("6");
}
if (next.equals("2")) {
list.remove("5");
}
if (next.equals("3")) {
list.add("3 found");
}
}
System.out.println(list);
}
}
使用CopyOnWriteArryList迭代修改不会报错,但是本次迭代器获取数据不会是最新改变的list中的数据,即iterator.next()还是获取的是之前的数据
public class CopyOnWriteArrayListDemo1 {
public static void main(String[] args) {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
System.out.println(next);
System.out.println("list is" + list);
if (next.equals("1")) {
list.add("6");
}
if (next.equals("2")) {
list.remove("5");
}
if (next.equals("3")) {
list.add("3 found");
}
}
System.out.println("最终的list:"+list);
}
}
⑤并发队列
1、阻塞队列
2、非阻塞队列
八·并发流程
①countDownLatch
一等多
**
* 描述: 工厂中,质检,5个工人检查,所有人都认为通过,才通过
*/
public class CountDownLatchDemo1 {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(5);
ExecutorService service = Executors.newFixedThreadPool(5);
for (int i = 0; i < 5; i++) {
final int no = i + 1;
Runnable runnable = () -> {
try {
//模拟工作时长
long l = (long) (Math.random() * 10000);
Thread.sleep(l);
System.out.println("No." + no + "完成了检查。用时:"+l+"ms");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
};
service.execute(runnable);
}
System.out.println("等待5个人检查完.....");
latch.await();
System.out.println("所有人都完成了工作,进入下一个环节。");
service.shutdown();
}
}
多等一
/**
* 描述: 模拟压测试时需要等到所有线程准备完毕再瞬时请求
*/
public class CountDownLatchDemo2 {
public static void main(String[] args) {
CountDownLatch begin = new CountDownLatch(1);
ExecutorService service = Executors.newFixedThreadPool(5);
AtomicInteger atomicInteger = new AtomicInteger();
ArrayList<Runnable> runnables = new ArrayList<>();
for (int i = 0; i < 5; i++) {
final int no = i + 1;
Runnable runnable = () -> {
try {
long l = (long) (Math.random() * 10000);
Thread.sleep(l);
System.out.println("Thread." + no + "准备完毕,等待压测。准备时长:"+l+"ms");
atomicInteger.getAndIncrement();
begin.await();
System.out.println("Thread." + no + "开始压测");
} catch (InterruptedException e) {
e.printStackTrace();
}
};
runnables.add(runnable);
}
runnables.forEach(service::submit);
//模拟检查线程是否准备完毕,准备发送请求
while (atomicInteger.get()<runnables.size()){
// System.out.println(atomicInteger.get());
}
System.out.println("总线程数为:"+runnables.size()+",执行标记位为:"+atomicInteger.get()+"线程准备完毕,开始压测!");
begin.countDown();
service.shutdown();
}
}
一等多、多等一协同
*
* 描述: 一等多、多等一协同
*/
public class CountDownLatchDemo1And2 {
public static void main(String[] args) throws InterruptedException {
CountDownLatch begin = new CountDownLatch(1);
CountDownLatch end = new CountDownLatch(5);
ExecutorService service = Executors.newFixedThreadPool(5);
AtomicInteger atomicInteger = new AtomicInteger();
ArrayList<Runnable> runnables = new ArrayList<>();
for (int i = 0; i < 5; i++) {
final int no = i + 1;
Runnable runnable = () -> {
try {
//模拟准备时间
long l = (long) (Math.random() * 10000);
Thread.sleep(l);
System.out.println("Thread." + no + "准备完毕,等待压测,准备时间:"+l+"ms");
atomicInteger.getAndIncrement();
begin.await();
System.out.println("Thread." + no + "开始压测");
//模拟请求时间
long l2 = (long) (Math.random() * 10000);
Thread.sleep(l2);
System.out.println("Thread." + no + "压测完毕,执行时间:"+l2+"ms");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
end.countDown();
}
};
runnables.add(runnable);
}
runnables.forEach(service::submit);
//模拟检查线程是否准备完毕,准备发送请求
while (atomicInteger.get()<5){
}
System.out.println("执行标记位为:"+atomicInteger.get()+"线程准备完毕,开始压测!");
begin.countDown();
end.await();
System.out.println("所有线程均请求完毕,压测结束");
service.shutdown();
}
}
②semaphore
基操
public class SemaphoreDemo {
static Semaphore semaphore = new Semaphore(3, true);
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(50);
for (int i = 0; i < 12; i++) {
service.submit(new Task());
}
service.shutdown();
}
static class Task implements Runnable {
@Override
public void run() {
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "拿到了许可证");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "释放了许可证");
semaphore.release();
}
}
}
③condition
public class ConditionDemo1 {
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
void method1() throws InterruptedException {
lock.lock();
try{
System.out.println("条件不满足,开始await");
condition.await();
System.out.println("条件满足了,开始执行后续的任务");
}finally {
lock.unlock();
}
}
void method2() {
lock.lock();
try{
System.out.println("准备工作完成,唤醒其他的线程");
condition.signal();
}finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
ConditionDemo1 conditionDemo1 = new ConditionDemo1();
new Thread(() -> {
try {
Thread.sleep(1000);
conditionDemo1.method2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
Thread.sleep(1000);
conditionDemo1.method1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
生产者消费者模式
public class ConditionDemo2 {
private int queueSize = 10;
private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);
private Lock lock = new ReentrantLock();
private Condition notFull = lock.newCondition();
private Condition notEmpty = lock.newCondition();
public static void main(String[] args) {
ConditionDemo2 conditionDemo2 = new ConditionDemo2();
Producer producer = conditionDemo2.new Producer();
Consumer consumer = conditionDemo2.new Consumer();
producer.start();
consumer.start();
}
class Consumer extends Thread {
@Override
public void run() {
consume();
}
private void consume() {
while (true) {
lock.lock();
try {
while (queue.size() == 0) {
System.out.println("队列空,等待数据");
try {
notEmpty.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.poll();
notFull.signalAll();
System.out.println("从队列里取走了一个数据,队列剩余" + queue.size() + "个元素");
} finally {
lock.unlock();
}
}
}
}
class Producer extends Thread {
@Override
public void run() {
produce();
}
private void produce() {
while (true) {
lock.lock();
try {
while (queue.size() == queueSize) {
System.out.println("队列满,等待有空余");
try {
notFull.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.offer(1);
notEmpty.signalAll();
System.out.println("向队列插入了一个元素,队列剩余空间" + (queueSize - queue.size()));
} finally {
lock.unlock();
}
}
}
}
}
④CyclicBarrier
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
@Override
public void run() {
System.out.println("所有人都到场了, 大家统一出发!");
}
});
for (int i = 0; i < 10; i++) {
new Thread(new Task(i, cyclicBarrier)).start();
}
}
static class Task implements Runnable{
private int id;
private CyclicBarrier cyclicBarrier;
public Task(int id, CyclicBarrier cyclicBarrier) {
this.id = id;
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
System.out.println("线程" + id + "现在前往集合地点");
try {
Thread.sleep((long) (Math.random()*10000));
System.out.println("线程"+id+"到了集合地点,开始等待其他人到达");
cyclicBarrier.await();
System.out.println("线程"+id+"出发了");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
九·AQS
①简介
②用法及源码
带share的是共享锁,不带的是独占锁
1、CountDownLatch
构造方法
await()
countDown()
2、Semaphore
构造方法
公平:
不公平:
aquire()
公平锁实现:
非公平锁实现:
释放许可证的方法release()
3、ReentrantLock
lock()
非公平锁的实现:
公平锁的实现:
unlock()
释放方法公平与非公平锁都是用的Sync里面方法
十·Future