线程的字符串字段上的 getter 和 setter 是否必须同步/

Should getter and setter on String field of a thread have to be synchronized/

我正在制作一个 Runnable,它会做一些独立的工作,但它的进度将由其他线程跟进。

为了做到这一点,我放置了一个私有字符串字段,其中包含我的线程的 "the state"。该线程将使用此字段的 setter 更新其进程,而其他线程将使用 getter 检索状态。 目前,我编写了以下代码并使用锁来同步我的 getter 和 setter。 但是不知道有没有必要

我想我的问题可以总结为: "Does affectation are atomic in 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");
        }
    }
}

没必要。没有任何东西会被破坏,因为这是一个原子操作。最坏的情况是您的 getter 将获得旧值。原子操作不需要锁。

现在最大的问题是 getter 获得绝对最新值有多重要?如果这与其他同步相关联,那么也许。将 volatile 关键字添加到 state 可能是避免数据变得太陈旧的好主意。

我想我找到了答案。 为了确保对字段的原子访问,您必须声明它 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");
        }
    }
}