2013-09-19 3 views
3

Я пишу класс на Java, который многопоточен, поскольку он инициализирует и использует отдельный поток для обновления своих частных полей.Класс internal thread-safety

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]; 
     } 
    } 
} 

Вопрос в том, является ли этот класс внутренним поточно-безопасным? Из того, что я прочитал относительно неизменяемых объектов, таких как Байт и т. Д., Является то, что они по сути являются потокобезопасными.

EDIT: добавлены значения по умолчанию для полей

ответ

7

Вопрос в том, является ли этот класс внутренним поточно-безопасным? Из того, что я прочитал относительно неизменяемых объектов, таких как Байт и т. Д., Является то, что они по сути являются потокобезопасными.

Проблема с защитой от потока, которую я вижу с вашим классом, заключается в том, что вы обновляете два поля, которые выглядят взаимосвязанными. Из условий гонки можно было бы увидеть новое значение channel и старое значение mode. Я бы использовал объект volatile ChannelMode вместо двух полей volatile.

public class ChannelMode { 
    private byte channel; 
    private byte mode; 
    public byte getChannel() { 
     return channel; 
    } 
    public byte getMode() { 
     return mode; 
    } 
} 

Хотя нет необходимости, я хотел бы использовать 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]); 

Если внутренняя резьба обновляет ChannelMode каждый так часто, то ваш класс должен быть поточно в том, что значения будут обновлены и атомарно памяти синхронизированы.

+0

поэтому для поддержания безопасности потоков полей классов я должен использовать класс AtomicReference , так что при чтении или записи полей он синхронизируется –

+0

Ну, 'volatile 'обеспечивает синхронизацию памяти. То, что делает 'AtomicReference' (которое использует внутреннюю ссылку' volatile'), обеспечивает _atomic_ обновление двух полей @GeoP. – Gray

+0

ahh Я вижу спасибо! –

1

Если изменить внутренние поля класс не является неизменным. Неизменяемый класс не меняется. Это означает, что ваш класс не является потокобезопасным.

Это правда, что если вы не выставляете какие-либо сеттеры или какой-либо другой метод, который изменяет ваш класс, он должен быть неизменным, но в этом случае вы меняете его внутренне. по сути поточно-безопасный означает, что он не может быть изменен, поэтому вам не нужно бояться, что разные потоки будут гоняться и испортить данные друг друга. Это, конечно, не так.

+1

Просто потому, что класс не является неизменным, не означает, что он не является потокобезопасным. Существуют также проблемы безопасности потоков, которые могут возникнуть, даже если класс _is_ immutable - например, проблемы видимости конструктора. – Gray

+0

Реальный вопрос заключается в том, что внутренний поток обновляет значения внешнего потока поточно-безопасным способом. – Gray

+0

@ Серый, я ответил на вопрос ОП. (S) он спросил, действительно ли это потокобезопасно, потому что это неизменно. Кроме того, в этом случае это нить. – Avi

1

Ваш класс не является потоковым. Причина: Если //get new data[]... занимает много времени, другие методы могут попытаться прочитать внутренние поля, прежде чем они будут инициализированы вашей внутренней нитью. Внутренний поток в конструкторе не остановит конструкцию объекта и инициализацию, поэтому пока данные не будут подготовлены, он может иметь несогласованное состояние.

+0

смотрите. –