背景
某些业务中因为使用HashMap这些线程不安全的结合类,如果因为线程不安全的问题导致了得到的结果我们的预期不一致,那么我们可以使用这些集合类对应的同步容器或者并发容器(JUC)包下。
集合类型 | 对应的并容器 | 补充 |
---|---|---|
Map | ConcurrentHashMap | |
Map | ConcurrentSkipListMap | |
List | CopyOnWriteArrayList | |
List | ConcurrentLinkedQueue | |
Set | CopyOnWriteArraySet | |
Set | ConcurrentSkipListSet |
Map
demo1
package com.mark.example.concurrent;
import com.mark.annotations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
/**
*
* author:Mark
* date:2018/7/31 11:53
*
* HashMap:线程不安全
* HashTable:线程安全,效率低,锁住整个表
* ConcurrentHashMap:采用锁分段机制
*
*/
@Slf4j
@ThreadSafe
public class ConcurrentHashMapTest {
public static int clientTotal = 5000;//请求总数
public static int threadTotal = 200;//同时并发执行的线程数
public static Map<Integer,Integer> map = new ConcurrentHashMap<>();
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();//线程池
final Semaphore semaphore = new Semaphore(threadTotal);//信号量,控制同时并发的线程数
CountDownLatch countDownLatch = new CountDownLatch(clientTotal);//计数器,保证线程执行完之后再进行其他的处理
for (int i = 0; i < clientTotal; i++) {
final int count = i;
executorService.execute(()->{
try {
semaphore.acquire();
update(count);
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();//关闭线程池
log.info("size:{}",map.size());
}
private static void update(int i) {//模拟并发的访问方法
map.put(i, i);
}
}
运行结果:线程安全
12:00:18.467 [main] INFO com.mark.example.concurrent.ConcurrentHashMapTest - size:5000
package com.mark.example.concurrent;
import com.mark.annotations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
import java.util.concurrent.*;
/**
* author:Mark
* date:2018/7/31 11:53
*/
@Slf4j
@ThreadSafe
public class ConcurrentSkipListMapTest {
public static int clientTotal = 5000;//请求总数
public static int threadTotal = 200;//同时并发执行的线程数
public static Map<Integer,Integer> map = new ConcurrentSkipListMap<>();
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();//线程池
final Semaphore semaphore = new Semaphore(threadTotal);//信号量,控制同时并发的线程数
CountDownLatch countDownLatch = new CountDownLatch(clientTotal);//计数器,保证线程执行完之后再进行其他的处理
for (int i = 0; i < clientTotal; i++) {
final int count = i;
executorService.execute(()->{
try {
semaphore.acquire();
update(count);
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();//关闭线程池
log.info("size:{}",map.size());
}
private static void update(int i) {//模拟并发的访问方法
map.put(i, i);
}
}
运行结果:线程安全
12:01:10.247 [main] INFO com.mark.example.concurrent.ConcurrentSkipListMapTest - size:500
List
CopyOnWriteArrayList
demo3
package com.mark.example.concurrent;
import com.mark.annotations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* author:Mark
* date:2018/7/31 11:56
*
* 写入并复制:适合并发的时候迭代操作
* 如果添加操作多时,效率低因为需要拷贝
*/
@Slf4j
@ThreadSafe
public class CopyOnWriteArrayListTest {
public static int clientTotal = 5000;//请求总数
public static int threadTotal = 200;//同时并发执行的线程数
public static List<Integer> list = new CopyOnWriteArrayList<>();
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();//线程池
final Semaphore semaphore = new Semaphore(threadTotal);//信号量,控制同时并发的线程数
CountDownLatch countDownLatch = new CountDownLatch(clientTotal);//计数器,保证线程执行完之后再进行其他的处理
for (int i = 0; i < clientTotal; i++) {
final int count = i;
executorService.execute(()->{
try {
semaphore.acquire();
update(count);
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();//关闭线程池
log.info("size:{}",list.size());
}
private static void update(int i) {//模拟并发的访问方法
list.add(i);
}
}
运行结果:线程安全
2:03:10.771 [main] INFO com.mark.example.concurrent.CopyOnWriteArrayListTest - size:5000
Set
CopyOnWriteArraySet
package com.mark.example.concurrent;
import com.mark.annotations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;
import java.util.Set;
import java.util.concurrent.*;
/**
* author:Mark
* date:2018/7/31 11:59
*/
@Slf4j
@ThreadSafe
public class CopyOnWriteArraySetTest {
public static int clientTotal = 5000;//请求总数
public static int threadTotal = 200;//同时并发执行的线程数
public static Set<Integer> set = new CopyOnWriteArraySet<>();
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();//线程池
final Semaphore semaphore = new Semaphore(threadTotal);//信号量,控制同时并发的线程数
CountDownLatch countDownLatch = new CountDownLatch(clientTotal);//计数器,保证线程执行完之后再进行其他的处理
for (int i = 0; i < clientTotal; i++) {
final int count = i;
executorService.execute(()->{
try {
semaphore.acquire();
update(count);
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();//关闭线程池
log.info("size:{}",set.size());
}
private static void update(int i) {//模拟并发的访问方法
set.add(i);
}
}
12:04:12.005 [main] INFO com.mark.example.concurrent.CopyOnWriteArraySetTest - size:5000
ConcurrentSkipListSet
package com.mark.example.concurrent;
import com.mark.annotations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.*;
/**
* author:Mark
* date:2018/7/31 11:57
*/
@Slf4j
@ThreadSafe
public class ConcurrentSkipListSetTest {
public static int clientTotal = 5000;//请求总数
public static int threadTotal = 200;//同时并发执行的线程数
public static Set<Integer> set = new ConcurrentSkipListSet<>();
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();//线程池
final Semaphore semaphore = new Semaphore(threadTotal);//信号量,控制同时并发的线程数
CountDownLatch countDownLatch = new CountDownLatch(clientTotal);//计数器,保证线程执行完之后再进行其他的处理
for (int i = 0; i < clientTotal; i++) {
final int count = i;
executorService.execute(()->{
try {
semaphore.acquire();
update(count);
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();//关闭线程池
log.info("size:{}",set.size());
}
private static void update(int i) {//模拟并发的访问方法
set.add(i);
}
}
运行结果:线程安全
12:04:57.362 [main] INFO com.mark.example.concurrent.ConcurrentSkipListSetTest - size:5000