我的程序在一个存储库上模仿工作。需要同步的资源为Repository
对象(用作monitor)中的阵列cells
。线程(RepoThread
类)被允许添加或从数组的单元格值中减去值,但只有当没有其他线程在相同的单元格上做同样的事情时。只要在不同的细胞上进行操作,RepoThread
s就会同时进行操作(加减)。当前正在处理的单元格将被视为"繁忙",其索引将存储在HashMap中。
我有这些类(:
import java.util.HashSet;
import java.util.Set;
public class Repository {
private int[] cells;
private Set<Integer> busyCells;
public Repository(int size, int initialValue) {
busyCells = new HashSet<Integer>();
cells = new int[size];
for (int i = 0; i < size; i++)
cells[i] = initialValue;
}
public synchronized void add(int index, int amount, int threadId) {
while (busyCells.contains((Integer) index)) { // cell is busy
try {
System.out.println("thread" + threadId
+ "will wait to ADD on cell" + index
+ ", busy cells:" + busyCells);
wait();
} catch (InterruptedException e) {
}
}
// cell is not busy now
busyCells.add(index);
cells[index] = cells[index] + amount;
busyCells.remove((Integer) index);
System.out.println("Thread n." + threadId
+ " just ADDED " + amount
+ " to cell " + index
+ ", new amount=" + cells[index]
+ ", busy cells: " + busyCells);
notifyAll();
}
public synchronized void remove(int index, int amount, int threadID) {
while (busyCells.contains((Integer) index)) {
System.out.println("thread n." + threadID
+ " tried to remove " + amount
+ " from cell " + index + ""
+ " but the amount is " + cells[index]
+ "busy cells:" + busyCells);
try {
wait();
} catch (InterruptedException e) {
System.out.println("interrupted");
}
}
busyCells.add(index);
cells[index] = cells[index] - amount;
busyCells.remove((Integer) index);
System.out.println("thread n." + threadID
+ " just REMOVED " + amount
+ " from cell " + index + ","
+ " new amount is " + cells[index]
+ ", busy cells: " + busyCells);
notifyAll();
}
public int size() {
return cells.length;
}
}
public class RepoThread extends Thread {
Repository mon;
int id;
int addOrRemove;
int index;
int amount;
public RepoThread(Repository mon, int id, int addOrRemove, int index, int amount) {
this.mon = mon;
this.id = id;
this.addOrRemove = addOrRemove;
this.index = index;
this.amount = amount;
}
public void run() {
if (addOrRemove == 1) {
mon.add(index, amount,id);
}else if(addOrRemove==2){
mon.remove(index, amount, id);
}else{
System.out.println("unknown operation requested");
}
}
}
public class TestRepository {
public static void main(String[] args) {
Repository repo = new Repository(10, 5);
RepoThread remover1 = new RepoThread(repo, 1, 2, 5, 8);
remover1.start();
RepoThread remover2 = new RepoThread(repo, 2, 2, 5, 4);
remover2.start();
RepoThread adder1 = new RepoThread(repo, 3, 1, 5, 4);
adder1.start();
RepoThread adder2 = new RepoThread(repo, 4, 1, 5, 2);
adder2.start();
RepoThread adder3 = new RepoThread(repo, 5, 1, 7, 4);
adder3.start();
RepoThread adder4 = new RepoThread(repo, 6, 1, 5, 4);
adder4.start();
}
}
我的问题是,似乎没有碰撞发生,因为我的add
和remove
方法是synchronized
。这意味着当任何线程正在添加或删除Repository
对象时,该对象被锁定,并且没有其他线程可以访问该数组,因为整个对象都被锁定,而不仅仅是繁忙的单元格。
我应该做什么改变,所以线程将能够做任何他们想要的存储库对象,只要他们做它在cells
数组的非繁忙单元?
如果我理解你的问题,你想直接锁定更精确的Cell,对吗?如果是这样…
一个选项可以是用同步块替换同步在cell对象本身(如果你创建一个数组的cell对象-意味着你创建一个cell类-)。
// Example
Cell [] cells = new Cell[nb];
// initialize the array as you need
// later on, in remove or add
synchronize (cells[i]) {
// your stuff
}
另一种选择是通过一个ReentrantLock数组来锁定,每个单元格一个。
ReentrantLock [] locks = new ReentrantLock[nb];
// fill the array of ReentranLock, one per cell
locks[cellRank].lock();
try {
// your stuff
} finally {
lock[cellRank].unlock();
}