使用Concurrent集合
2023-02-18 15:31:04 时间
我们在前面已经通过ReentrantLock
和Condition
实现了一个BlockingQueue
:
public class TaskQueue {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private Queue<String> queue = new LinkedList<>();
public void addTask(String s) {
lock.lock();
try {
queue.add(s);
condition.signalAll();
} finally {
lock.unlock();
}
}
public String getTask() {
lock.lock();
try {
while (queue.isEmpty()) {
condition.await();
}
return queue.remove();
} finally {
lock.unlock();
}
}
}
BlockingQueue
的意思就是说,当一个线程调用这个TaskQueue
的getTask()
方法时,该方法内部可能会让线程变成等待状态,直到队列条件满足不为空,线程被唤醒后,getTask()
方法才会返回。
因为BlockingQueue
非常有用,所以我们不必自己编写,可以直接使用Java标准库的java.util.concurrent
包提供的线程安全的集合:ArrayBlockingQueue
。
除了BlockingQueue
外,针对List
、Map
、Set
、Deque
等,java.util.concurrent
包也提供了对应的并发集合类。我们归纳一下:
interface | non-thread-safe | thread-safe |
---|---|---|
List | ArrayList | CopyOnWriteArrayList |
Map | HashMap | ConcurrentHashMap |
Set | HashSet / TreeSet | CopyOnWriteArraySet |
Queue | ArrayDeque / LinkedList | ArrayBlockingQueue / LinkedBlockingQueue |
Deque | ArrayDeque / LinkedList | LinkedBlockingDeque |
使用这些并发集合与使用非线程安全的集合类完全相同。我们以ConcurrentHashMap
为例:
Map<String, String> map = new ConcurrentHashMap<>();
// 在不同的线程读写:
map.put("A", "1");
map.put("B", "2");
map.get("A", "1");
因为所有的同步和加锁的逻辑都在集合内部实现,对外部调用者来说,只需要正常按接口引用,其他代码和原来的非线程安全代码完全一样。即当我们需要多线程访问时,把:
Map<String, String> map = new HashMap<>();
改为:
Map<String, String> map = new ConcurrentHashMap<>();
就可以了。
java.util.Collections
工具类还提供了一个旧的线程安全集合转换器,可以这么用:
Map unsafeMap = new HashMap();
Map threadSafeMap = Collections.synchronizedMap(unsafeMap);
但是它实际上是用一个包装类包装了非线程安全的Map
,然后对所有读写方法都用synchronized
加锁,这样获得的线程安全集合的性能比java.util.concurrent
集合要低很多,所以不推荐使用。
小结
使用java.util.concurrent
包提供的线程安全的并发集合可以大大简化多线程编程:
多线程同时读写并发集合是安全的;
尽量使用Java标准库提供的并发集合,避免自己编写同步代码。
相关文章
- Java中使用DOM4J来生成xml文件和解析xml文件
- Java调用腾讯云短信接口,完成验证码的发送(不成功你来砍我!!)
- Java反序列化漏洞学习
- Java核心知识体系3:异常机制详解
- Java核心知识体系2:注解机制详解
- Java核心知识1:泛型机制详解
- Java:导出Excel大批量数据的优化过程
- Springboot返回数据null转空字符串
- java记录项目的UV值与PV值
- 小米手机自拍图标-小米Civi 1S体验:这次,男生也能自拍美颜了
- java文件网络路径转MultipartFile
- 百度短信接口以及人脸实名认证接口
- 怎样使用摄像机-索尼高清摄像机使用方法简要介绍【教程】
- 小米手机自拍图标-小米Civi 1S vs 小米9:最强自拍手机的后置镜头咋样?
- spring框架
- hexo博客插入音视频
- java实用小功能案例
- Excel自动化办公
- Open-CV图像处理
- open-CV的初步学习