我的程序模仿存储库的工作。
必须同步的资源是cells
对象中的数组Repository
(用作监视器)。
允许线程(RepoThread
类)向数组的单元格值添加或减去值,但仅当没有其他线程在相同的单元格上执行相同操作时。 RepoThread
只要在不同的单元格上执行操作,就会同时执行操作(加/减)。
当前正在处理的单元格将被视为“繁忙”,其索引将存储在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
对象被锁定,并且没有其他线程可以访问该数组,因为整个对象被锁定而不仅仅是繁忙的单元。
我应该做些什么改变,以便线程能够在Repository对象上做任何他们想做的事情,只要他们在cells
数组的非繁忙单元格上做它?
答案 0 :(得分:2)
如果我理解你的问题,你想直接锁定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();
}