Java - 多线程不可变对象

时间:2014-03-16 21:12:55

标签: java multithreading

我有这堂课:

class S2Es2SharedState {
    public int x;
    public int y;
}

用于在循环内的每个线程中共享s2Es2SharedState对象:

class S2Es2Worker implements Runnable {
    private final int id;
    private S2Es2SharedState state;
    private final int delay;
    private int numErrors = 0;

    public S2Es2Worker(final int id, final S2Es2SharedState state,
            final int delay) {
        this.state = state;
        this.delay = delay;
        this.id = id;
        this.numErrors = 0;
        System.out.println("Worker " + id + ": created with " + delay
                + " ms delay");
    }

    @Override
    public void run() {
        boolean check = true;
        System.out.println("Worker " + id + ": started");

        for (int i = 0; i < 150; i++) {
            state.x++;

            try {
                Thread.sleep(delay);
            } catch (final InterruptedException e) {
                // do nothing
            }

            state.y++;  
        }
    }
}

在这个程序中工作10个线程,其中每个线程都进入循环并增加共享对象的x和y值的150倍,因此共享对象的x和y的最终结果是1500。如果我没有改变任何东西,这个程序有竞争条件的问题,所以为了解决这个问题,我使用了锁(并且它可以工作)。
但是现在我想使用不可变对象而不是锁来解决竞争条件的问题。所以我用这种方式改变了共享对象的类:

final class S2Es2SharedState {
    private final int x;
    private final int y;

    public S2Es2SharedState(final int x, final int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public S2Es2SharedState incrementX() {
        return new S2Es2SharedState(x+1, y);
    }

    public S2Es2SharedState incrementY() {
        return new S2Es2SharedState(x, y+1);
    }
}

并且在run()方法中我以这种方式更改了状态变量:

class S2Es2Worker implements Runnable {
     ....
     private volatile S2Es2SharedState state;
     ....

在for循环中我做了这个编辑:

for (int i = 0; i < 150; i++) {
            state = state.incrementX();

            try {
                Thread.sleep(delay);
            } catch (final InterruptedException e) {
                // do nothing
            }

            state = state.incrementY();

        }
    }

但我不知道为什么最终结果是共享对象而不是x = 1500且y = 1500
150两个变量

如何解决问题与使用不可变对象的条件的竞争?

1 个答案:

答案 0 :(得分:0)

我假设您创建了一个S2Es2SharedState(使用更简单的名称来提问)

 S2Es2SharedState state = new S2Es2SharedState(0, 0)

并将其传递给类似

S2Es2Worker个实例
for (int i = 0; i < 10;i++) {
    S2Es2Worker worker = new S2Es2Worker(i, state, 5);
    new Thread(worker).start();
}

在java中,所有内容都按值传递。因此,使用state作为方法参数,将传递引用值的副本。

所以这个领域

private volatile S2Es2SharedState state;

也引用同一个对象。但是,如果您更改字段state所持有的引用,例如使用

state = state.incrementX();

不影响任何其他参考文献。