Java同步对象属性-同步是否获取所有锁?

bn31dyow  于 2023-03-28  发布在  Java
关注(0)|答案(1)|浏览(136)

https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html说“在这个例子中,addName方法需要同步lastName和nameCount的更改,但也需要避免同步调用其他对象的方法。(从同步代码调用其他对象的方法可能会产生在Liveness一节中描述的问题。)”
我实际上想同步另一个对象。有3个类,AdminImpl,UserImpl,ServerState。
ServerState的同一示例是AdminImpl和UserImpl中的属性。
如果我用synchronized(this)在UserImpl中编写一个临界区,它会同时获得UserImpl和作为UserImpl属性的ServerState示例的锁吗?(不同的)关键部分,因为要在AdminImpl的同步部分中,它需要同时获得这两个锁(AdminImpl和ServerState的),并且不能获取第二个,因为它是由UserImpl获取的?
我发现了一些关于同步的问题,例如java method synchronization objectConfusing Java synchronized method, synchronized(this), and synchronized classWhat's the difference between synchronized(this) and synchronized(some other object)
但没有一个涉及这一点

jm81lzqq

jm81lzqq1#

同步并不查看它所锁定的示例的细节,它只是在每个Java对象都具有的“内在锁”上获取一个锁。
因此,它对第一个对象可能在其字段中引用的其他对象没有影响。
这里有一个例子,我认为说明你的问题。
ServerState类包含一个可变的String,名为state,方法ServerState.addStringString追加到state
编写addString方法是为了保证线程安全问题--它在获取state的当前值和将新值赋给state之间休眠。
运行该程序,您将看到state的最终值是admin,而我们期望的是useradmin
确保您了解为什么会发生这种情况。
您可以尝试将synchronized添加到两个setStateString方法中,您会发现这没有什么区别。
现在只需将addString改为synchronized,这样就解决了线程安全问题,因为现在state字段的阅读和更新是原子性的--从其他线程的Angular 来看,这两个操作同时发生。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class UserImpl {
    private final ServerState state;

    UserImpl(ServerState state) {
        this.state = state;
    }

    public synchronized void setStateString(String s) {
        state.addString(s);
    }
}

class AdminImpl {
    private final ServerState state;

    AdminImpl(ServerState state) {
        this.state = state;
    }

    public synchronized void setStateString(String s) {
        state.addString(s);
    }
}

class ServerState {
    private volatile String state = "";

    public void addString(String s) {
        String oldState = state;
        System.out.println(Thread.currentThread().getName() + " In addString: adding " + s + ", oldState = " + oldState);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        state = oldState + s;
        System.out.println(Thread.currentThread().getName() + " In addString: set " + state);
    }

    public String getState() {
        return state;
    }
}

public class X {
    public static void main(String[] args) throws InterruptedException {
        ServerState state = new ServerState();
        AdminImpl admin = new AdminImpl(state);
        UserImpl user = new UserImpl(state);
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.submit(() -> user.setStateString("user"));
        executorService.submit(() -> admin.setStateString("admin"));
        executorService.shutdown();
        executorService.awaitTermination(2500L, TimeUnit.MILLISECONDS);
        System.out.println(state.getState());
    }
}

相关问题