Q1)我创建了一个基于链表的数据库连接池实现。需要连接的线程 poll() 从列表中获取连接,线程使用 add() 或 addFirst() 释放连接。在测试过程中,我注意到,即使一个线程使用synchronized(ll) {这里有一些代码}锁定了列表,其他线程也能够从列表中 poll() 出连接。这个测试让我得出结论,只有 {} 中的代码块才能保证一次由 1 个线程执行,但对象本身(即 ll )不会被锁定,其他线程仍然可以在其上写入。那是对的吗 ??那把ll当monitor有什么用呢?我也可以使用同步(this)..
Q2)如果我在创建列表期间使用 Collections.synchronizedList() 将链接列表创建为线程安全的,那么我可以摆脱同步块(synchronized block)吗?假设我有两种单独的方法来获取连接和释放连接。目前这两种方法都使用同步块(synchronized block)来获取/释放连接。
Q3)如果我决定使用非阻塞列表,例如 ConcurrentLinkedQueue(我们有 JDK 1.5),这对我们的情况会有帮助。我们的峰值连接使用量是 30,但我们没有在代码中施加任何限制,因此连接可以无限增长。我们计划编写一个计时器任务,该任务将在夜间运行并关闭列表头部的一些连接(旧连接),但为了执行业务逻辑,我们更愿意使用队列尾部的连接,因为这些连接是最新发布的连接,因此拥有非陈旧连接的可能性很高。但由于它是一个 fifo 队列,所以我无法从队列尾部 poll() 数据,所以我被迫使用来自队列头的可能陈旧的连接。所以基本上我需要的是用于执行业务逻辑的类似堆栈的功能,以及用于实现计时器任务的类似队列的功能。您可以建议的任何数据结构。
最佳答案
好的,你有一些 list :
LinkedList ll = ...;
在 ll
上同步不会阻止其他线程访问列表或修改列表:
synchronized(ll) {
...protected code...
// This does NOT prevent other threads from examining or updating
// ll while the protected code runs.
}
synchronized
block 唯一阻止的是,它阻止其他线程同时在同一对象上同步。
同步某些数据结构(例如链表)的原因是,当一个线程必须创建临时无效状态才能完成其工作时,防止其他线程看到该结构处于无效状态。
为了使其正常工作,创建临时错误状态的代码块必须同步,并且必须在同一个对象上同步必须防止看到错误状态的每个代码块。
<小时/>这是没有用的,因为永远不会允许其他线程在ll
上同步:
public void run() {
synchronized(ll) {
while(true) {
...
}
}
}
您通常希望保持同步块(synchronized block)尽可能短:您希望代码快速进入和退出,以最大限度地减少其他线程等待轮到的时间。
关于java - synchronized 关键字没有锁定链表,其他线程仍在从中轮询对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35694696/