类内部线程安全

Geo*_*o P 3 java multithreading thread-safety

我正在用Java编写一个内部多线程的类,因为它初始化并使用一个单独的线程来更新其私有字段.

class Foo {
    private volatile Byte channel = new Byte(0);
    private volatile Byte mode = new Byte(0);

    public Foo() {
        Thread t = new Thread(new UpdateFields());
        t.setDaemon(true);
        t.start();
    }

    public Byte getChannel() {
        return this.channel;
    }  

    public Byte getMode() {
        return this.mode;
    }

    private class UpdateFields implements Runnable {
        @Override public void run() {
            Byte data[];
            //get new data[]...
            channel = data[0];
            mode = data[1];
        }
    } 
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,这个类内部是线程安全的吗?从我读到的有关不可变对象(如Byte等)的内容来看,它们本质上是线程安全的.

编辑:向字段添加默认值

Gra*_*ray 7

我的问题是,这个类内部是线程安全的吗?从我读到的有关不可变对象(如Byte等)的内容来看,它们本质上是线程安全的.

我在您的课程中看到的线程安全问题是您正在更新两个看起来相关的字段.由于竞争条件,有可能看到一个新channel值和一个旧mode值.我会使用一个volatile ChannelMode对象而不是你的两个volatile字段.

public class ChannelMode {
    private byte channel;
    private byte mode;
    public byte getChannel() {
       return channel;
    }
    public byte getMode() {
       return mode;
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然没有必要,但我喜欢使用Atomic*类而不是volatile直接使用,所以我会使用AtomicReference<ChannelMode>.所以你的代码看起来像:

private AtomicReference<ChannelMode> channelModeRef =
    new AtomicReference<ChannelMode>(
        new ChannelMode(INITIAL_CHANNEL, INITIAL_MODE));
...
Byte data[];
// get new data[]...
// atomic operation to set the new channel-mode
channelModeRef.set(new ChannelMode(data[0], data[1]);
Run Code Online (Sandbox Code Playgroud)

如果您的内部线程ChannelMode经常更新,那么您的类应该是线程安全的,因为值将以原子方式更新并且内存正确同步.

  • @Gray原子参考在这里没什么价值.您真正的改变是将通道和模式封装在一个单独的不可变对象中.对"ChannelMode"的引用总是指向新版本或旧版本.调用`getChannel()`和`getMode()`仍然可以跨越变化.你当然可以添加一个`getChannelMode()`方法,但是`AtomicReference`什么都不买. (3认同)