我在学校的java项目上工作,你必须处理多线程程序。 我需要一个在多个线程之间共享的类,它基本上是一个必须管理并发访问的值矩阵,它看起来像:
public class CacheMatrix{
private MyType[][] cachedItems;
public CacheMatrix(int size){
this.cachedItems = new MyType[size][size];
}
public MyType readItem(int x, int y){...}
public void storeItem(int x, int y, MyType item){...}
}
我正要使用ReentrantReadWriteLock矩阵来管理它,每个项目一个,但我意识到矩阵大小大约是10 ^ 3 X 10 ^ 3所以我会有100万个锁!
你认为这是要走的路吗? (可以创建这么多锁吗?)
考虑到使用此类的线程数量限制为N(N范围从2到8),您能找到一种更好的方法,几乎只保留最小互斥但使用较少的锁定吗?
感谢您的支持!
答案 0 :(得分:1)
您可以考虑实施lock striping以减少锁定数量并保持性能。
基本上,会创建一个包含mylockscount = min(concurrencylevel, size)
锁的内部数组。
无论何时发生读/写操作,您都可以锁定,例如mylocks[somehashfunction(x, y) % mylockscount]
。
这样,锁的数量应该只与并发线程数一致,而不是矩阵的大小。
答案 1 :(得分:0)
另一种选择是将MyType[][]
替换为AtomicReference<MyType>[][]
;在这种情况下,void storeItem
将变为boolean storeItem(int x, int y, MyType oldValue, MyType newValue)
,如果oldValue
不等于当前在[x][y]
保持的值(在您要调用的表面下AtomicReference#compareAndSet(oldValue, newValue)
,则返回false })。这样你就没有任何锁,你需要在storeItem
返回false的情况下实现重试逻辑
如果MyType
是基元,例如int
,然后使用适当的原子基元,例如AtomicInteger
代替AtomicReference
答案 2 :(得分:0)
关于只是使访问方法同步?
public synchronized MyType readItems(...){...}
答案 3 :(得分:0)
我想到了两种可能的情景:
1)使用单个锁。这有点天真,但它可以解决你的问题。
2)仅锁定ROWS或COLUMNS。如果你打算随机地一次访问矩阵一个项目,我认为这应该做得很好:
public class CacheMatrix
{
private MyType[][] cachedItems;
public CacheMatrix(int size) {
this.cachedItems = new MyType[size][size];
}
public MyType readItem(int x, int y) {
synchronized (cachedItems[x]) {
return cachedItems[x][y];
}
}
public void storeItem(int x, int y, MyType item) {
synchronized (cachedItems[x]) {
this.cachedItems[x][y] = item;
}
}
}