JUCHashMap 非安全容器bing
Posted 鸟随二月
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUCHashMap 非安全容器bing相关的知识,希望对你有一定的参考价值。
文章目录
JUC(Java并发包)
java.util.concurrent包下的类
JUC包下的所有类都是线程安全的,JUC下有:
1.ReentrantLock(可重入锁)
2.Semaphore(信号量)
// 创建信号量
Semaphore semaphore = new Semaphore(2);
// 创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10,
0, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000));
// 执行任务 1
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
" 到达停车场门口");
try {
Thread.sleep(1000);
// 尝试获取锁
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 执行到此行代码表示已经获取到了停车位
System.out.println(Thread.currentThread().getName() +
" 进入了停车场");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
" 离开了停车场");
// 释放锁
semaphore.release();
}
});
// 执行任务 2
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
" 到达停车场门口");
try {
Thread.sleep(1000);
// 尝试获取锁
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 执行到此行代码表示已经获取到了停车位
System.out.println(Thread.currentThread().getName() +
" 进入了停车场");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
" 离开了停车场");
// 释放锁
semaphore.release();
}
});
// 执行任务 2
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
" 到达停车场门口");
try {
Thread.sleep(1000);
// 尝试获取锁
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 执行到此行代码表示已经获取到了停车位
System.out.println(Thread.currentThread().getName() +
" 进入了停车场");
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
" 离开了停车场");
// 释放锁
semaphore.release();
}
});
// 执行任务 2
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
" 到达停车场门口");
try {
Thread.sleep(1000);
// 尝试获取锁
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();
}
});
}
3. CountDownLatch(计数器)
等待所有的线程进入某个步骤之后,再统一执行某个流程。
public static void main(String[] args) throws InterruptedException {
// 创建 CountDownLatch
CountDownLatch countDownLatch =
new CountDownLatch(3);
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10,
0, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100));
for (int i = 0; i < 6; i++) {
// 执行任务
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
" 开跑");
int num = new Random().nextInt(5);
num += 1;
try {
Thread.sleep(num * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
" 到达了终点");
// 计数器 -1
countDownLatch.countDown();
}
});
}
// 等待所有的选手都到达终点,等待计时器为 0,在执行之后的结果
countDownLatch.await();
System.out.println("比赛结束,宣布成绩");
}
CountDownLauth执行的原理:
就是内有有一个计数器,当执行了countDown计时器-1,直到减到О那么这个计时器就使用完毕了,就可以执行await之后的代码了。
CountDownLauth 缺点:计时器只能使用一次。
4. CyclicBarrier(循环屏障)
public static void main(String[] args) throws InterruptedException {
CyclicBarrier cyclicBarrier =
new CyclicBarrier(2, new Runnable() {
@Override
public void run() {
System.out.println("-----------到达了屏障-----------");
}
});
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10,
0, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000));
for (int i = 1; i < 5; i++) {
final int finalI = i;
executor.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(finalI * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
" 进入了任务");
try {
// 等待其他线程执行
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
" 执行结束");
}
});
}
}
CyclicBarrie执行原理:内有一个计数器,每次线程执行到 await 方法的时候,计时器+1,直到计时器个数等于创建时声明的格式的时候,就会突破屏障,执行之后的代码;在突破屏障之后计时器清零可以进行下一轮的执行了。
HashMap 非安全容器
多线程下的问题:
JDK 1.7 头插法->死循环
单线程时
多线程时
1.
2.e2执行完时
3.e1继续执行
JDK 1.8尾插法-〉数据覆盖
HashMap的安全版本:ConcurrentHashMap
ConcurrentHashMap 实现线程安全原理是在进修改操作的时候(put),会在进入方法之后加锁,并且在操作完成之后释放锁,所以不会有线程安全的问题。
ConcurrentHashMap 优化:是将HashMap 分成多个sengment对每个sengment分别进行加锁,这样就可以保证。多线程如果操作的不是同一个sengment就不需进行排队处理了,从而提高了程序的执行效果。
分段锁:锁粒度更小,性能更高。
HashMap是非线程安全的
HashTable ->线程安全的(在put上使用的时synchronized)整体给对象进行加锁
以上是关于JUCHashMap 非安全容器bing的主要内容,如果未能解决你的问题,请参考以下文章