Java 多线程访问LinkedList中的线程安全
我的应用程序需要保留对特定资源请求的访问日志,多个线程将记录日志条目。唯一相关的信息是请求的时间戳,正在检索的统计数据将是在最后X秒内发生的请求数。返回给定秒数的统计信息的方法还需要支持多个线程 我正在考虑使用我不太熟悉的框架来处理并发处理,因此提出了这个问题。这是我的密码:Java 多线程访问LinkedList中的线程安全,java,multithreading,concurrency,locking,Java,Multithreading,Concurrency,Locking,我的应用程序需要保留对特定资源请求的访问日志,多个线程将记录日志条目。唯一相关的信息是请求的时间戳,正在检索的统计数据将是在最后X秒内发生的请求数。返回给定秒数的统计信息的方法还需要支持多个线程 我正在考虑使用我不太熟悉的框架来处理并发处理,因此提出了这个问题。这是我的密码: import java.util.LinkedList; import java.util.concurrent.locks.ReentrantLock; public class ConcurrentRecordSta
import java.util.LinkedList;
import java.util.concurrent.locks.ReentrantLock;
public class ConcurrentRecordStats
{
private LinkedList<Long> recLog;
private final ReentrantLock lock = new ReentrantLock();
public LinkedConcurrentStats()
{
this.recLog = new LinkedList<Long>();
}
//this method will be utilized by multiple clients concurrently
public void addRecord(int wrkrID)
{
long crntTS = System.currentTimeMillis();
this.lock.lock();
this.recLog.addFirst(crntTS);
this.lock.unlock();
}
//this method will be utilized by multiple clients concurrently
public int getTrailingStats(int lastSecs)
{
long endTS = System.currentTimeMillis();
long bgnTS = endTS - (lastSecs * 1000);
int rslt = 0;
//acquire the lock only until we have read
//the first (latest) element in the list
this.lock.lock();
for(long crntRec : this.recLog)
{
//release the lock upon fetching the first element in the list
if(this.lock.isLocked())
{
this.lock.unlock();
}
if(crntRec > bgnTS)
{
rslt++;
}
else
{
break;
}
}
return rslt;
}
}
import java.util.LinkedList;
导入java.util.concurrent.locks.ReentrantLock;
公共类ConcurrentRecordStats
{
私有链接列表重新登录;
private final ReentrantLock lock=new ReentrantLock();
公共链接的ConcurrentStats()
{
this.recLog=new LinkedList();
}
//此方法将由多个客户端同时使用
公共无效添加记录(int wrkrID)
{
长crntTS=System.currentTimeMillis();
this.lock.lock();
this.recLog.addFirst(crntTS);
这个.lock.unlock();
}
//此方法将由多个客户端同时使用
公共int getTrailingStats(int lastSecs)
{
long-endTS=System.currentTimeMillis();
长bgnTS=endTS-(lastSecs*1000);
int rslt=0;
//只有在我们读取之前,才能获取锁
//列表中的第一个(最新)元素
this.lock.lock();
for(长crntRec:this.recLog)
{
//在获取列表中的第一个元素时释放锁
if(this.lock.isLocked())
{
这个.lock.unlock();
}
如果(crntRec>bgnTS)
{
rslt++;
}
其他的
{
打破
}
}
返回rslt;
}
}
我的问题是:
ReentrantLock
会确保线程安全吗getRailingStats
中使用锁synchronized
块执行所有这些操作吗?我之所以使用锁,是因为我想在R和W部分中都使用相同的锁,这样列表中第一个元素(最近添加的条目)的写入和读取一次只在一个线程中完成,而仅使用synchronized
无法做到这一点这些锁可能是一个主要的性能瓶颈。另一种方法是:使用
offerFirst
添加新元素,并使用(弱一致的)迭代器(不会抛出ConcurrentModificationException
)代替for-each循环。优点是,这将比您的实现或synchronizedList
实现的性能好得多,但缺点是迭代器的一致性很弱-thread1可能会在thread2遍历列表时向列表中添加元素,这意味着thread2不会计算这些新元素。但是,这在功能上相当于让thread2锁定列表,使thread1无法添加到列表中-无论哪种方式,thread2都不会计算新元素。我只是想知道,为什么不简单地使用public列表集合。synchronizedList(列表列表)
获取线程安全列表?这会消除锁的需要吗?Java.util.concurrent.ConcurrentLinkedQue使用弱一致迭代器是线程安全的。弱一致迭代器的意思是什么?javadoc中有很好的解释:如果T2在T1迭代时添加元素,这不是问题,因为T1不包括新的元素,但我的LinkedList也不会出现ConcurrentModificationException
,因为我只遍历以前输入的元素,getTrailingStats
中的锁负责在保存第一个现有元素时不插入新元素read@amphibient链表的迭代器不够聪明,无法知道您正在以这样的方式使用它,即对链表的修改无关紧要—它使用一个计数器来计算对链表的修改次数,然后迭代器所做的修改次数,如果这些计数器不匹配,它将抛出一个ConcurrentModificationException
,这可能发生在您解锁锁后,同时仍然通过for-each循环在列表中进行迭代。您需要在整个循环中保持锁
,以避免出现异常。实际上,我模拟了多个线程在其他线程读取时写入,这不会导致异常