根据Java中监视器对象的特定属性同步线程



我的程序在一个存储库上模仿工作。需要同步的资源为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();
    }
}

我的问题是,似乎没有碰撞发生,因为我的addremove方法是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();
}

最新更新