Должен ли геттер и сеттер в поле String потока быть синхронизированы/

Я делаю Runnable, который будет выполнять некоторую независимую работу, но за его прогрессом будет следить другой поток.

Для этого я поместил приватное строковое поле, содержащее «состояние» моего потока. Поток обновит свой процесс, используя метод установки этого поля, а другой поток получит состояние, используя метод получения. На данный момент я написал следующий код и использую блокировку для синхронизации моего геттера и сеттера. Но мне интересно, нужно ли это.

Я предполагаю, что мой вопрос можно было бы резюмировать следующим образом: «Является ли аффектация атомарной в Java»

Заранее спасибо, если вы нашли время, чтобы прочитать мой вопрос.

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class FollowedThread implements Runnable {
    private String state;
    private final Lock lock;

    public FollowedThread() {
        lock = new ReentrantLock();
    }

    public void setState(String state) {
        lock.lock();
        try {
            this.state = state;
        } finally {
            lock.unlock();
        }
    }

    public String getState() {
        String result;
        lock.lock();
        try {
            result = state;
        } finally {
            lock.unlock();
        }

        return result;
    }

    @Override
    public void run() {
        setState("Step 1 running");
        try {
            Thread.sleep(1000);
            setState("Step 2 running");
            Thread.sleep(2000);
            setState("Step 3 running");
            Thread.sleep(3000);
            setState("Thread finished");
        } catch (InterruptedException e) {
            setState("Thread interrupted");
        }
    }
}

person Luc DUZAN    schedule 11.03.2015    source источник
comment
Не по теме, но зачем использовать Lock, когда можно просто сделать synchronized(state)?   -  person NiziL    schedule 11.03.2015
comment
Похоже, вы можете найти этот пост полезным stackoverflow.com/questions/8195506/   -  person aarbor    schedule 11.03.2015
comment
@Nizil, спасибо, верно, я сделал это, потому что не знаком с параллелизмом в Java. Это рефлекс моей домашней работы по системе C, когда я был студентом.   -  person Luc DUZAN    schedule 11.03.2015
comment
Просто объявите его volatile, никакой другой синхронизации не требуется. Ссылки на объекты назначаются атомарно.   -  person Alex Salauyou    schedule 11.03.2015


Ответы (2)


Думаю, я нашел свой ответ. Чтобы обеспечить атомарный доступ к полю, вы должны объявить его volatile. С ним мой код становится:

package com.afklm.myactu.util;

public class FollowedThread implements Runnable {
    private volatile String state;

    public void setState(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

    @Override
    public void run() {
        setState("Step 1 running");
        try {
            Thread.sleep(1000);
            setState("Step 2 running");
            Thread.sleep(2000);
            setState("Step 3 running");
            Thread.sleep(3000);
            setState("Thread finished");
        } catch (InterruptedException e) {
            setState("Thread interrupted");
        }
    }
}
person Luc DUZAN    schedule 11.03.2015
comment
Это сработает. Следовательно, теперь вы можете полностью избавиться от блокировки. - person ReneS; 11.03.2015
comment
На самом деле, вы должны использовать volatile, чтобы обеспечить отношение происходит до. Это приводит к очистке кеша процессора/локального потока и повторному чтению обновленного значения из основной памяти. ТАК, что все потоки смогут прочитать обновленное значение. Поскольку вы просто переназначаете ссылку, volatile будет достаточно. Используйте синхронизацию, когда внутри блока метода/кода есть несколько инструкций. - person TheLostMind; 11.03.2015

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

Теперь главный вопрос: насколько важно, чтобы геттер получал самое последнее значение? Если это завязано на другую синхронизацию, то может быть. Добавление ключевого слова volatile к state, вероятно, является хорошей идеей, чтобы данные не стали слишком устаревшими.

person Necreaux    schedule 11.03.2015
comment
Согласно этой статье javamex.com/tutorials/synchronization_volatile.shtml. Если вы не объявите, что ваше поле имеет volatif, это не гарантирует, что аффектация атомарна. - person Luc DUZAN; 11.03.2015
comment
у вас есть надежный источник, подтверждающий, что аффектация объекта атомарна? - person Luc DUZAN; 13.03.2015