根据Java

时间:2015-08-16 16:40:08

标签: java multithreading

我的程序模仿存储库的工作。 必须同步的资源是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();

    }
}

我的问题是,似乎没有发生冲突,因为我的addremove方法是synchronized。这意味着当任何线程正在执行添加或删除时,Repository对象被锁定,并且没有其他线程可以访问该数组,因为整个对象被锁定而不仅仅是繁忙的单元。

我应该做些什么改变,以便线程能够在Repository对象上做任何他们想做的事情,只要他们在cells数组的非繁忙单元格上做它?

1 个答案:

答案 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();
}