Java中非final对象同步的正确方法

Java中非final对象同步的正确方法,java,concurrency,thread-safety,Java,Concurrency,Thread Safety,我想用锁保护一个物体 我没有选择互斥体,因为“try..catch”的语法很难看 浏览stackoverflow,我得出结论,这就是如何正确实现我的目标: class MyClass { private final Object lock = new Object(); private Channel channel = null; public void setChannel() { synchronized (lock) {

我想用锁保护一个物体

我没有选择互斥体,因为“try..catch”的语法很难看

浏览stackoverflow,我得出结论,这就是如何正确实现我的目标:

class MyClass {
    private final Object lock = new Object();
    private Channel channel = null;

    public void setChannel() {
        synchronized (lock) {
            channel = new Channel();
            synchronized (channel) {
                // setup channel
            }
        }
    }

    public void unsetChannel() {
        synchronized (lock) {
            synchronized (channel) {
                channel.close();
            }
        channel = null;
        }
    }

    public boolean isSet() {
        synchronized (lock) {
            if (channel == null)
                return false;
            synchronized (channel) {
                return channel.isActive();
            }
        }
    }
}
但是它看起来很难看而且很难读


如何提高解决方案的可读性?

您可以简化锁定策略:

class MyClass {
    private final Object lock = new Object();
    private Channel channel = null;

    public void setChannel() {
        // other code can go here

        synchronized (lock) {
            channel = new Channel();
            // setup channel
        }

        // other code can go here
    }

    public void unsetChannel() {

        // other code can go here

        synchronized (lock) {
            channel.close();
            channel = null;
        }

        // other code can go here
    }

    public boolean isSet() {
        synchronized (lock) {
            if (channel == null) {
                return false;
            }
            return channel.isActive();
        }
    }
}
实际上,
lock
对象保护对通道变量的任何访问


编辑以显示未与
频道
交互的其他代码可能位于锁定之外的位置。

您可以简化锁定策略:

class MyClass {
    private final Object lock = new Object();
    private Channel channel = null;

    public void setChannel() {
        // other code can go here

        synchronized (lock) {
            channel = new Channel();
            // setup channel
        }

        // other code can go here
    }

    public void unsetChannel() {

        // other code can go here

        synchronized (lock) {
            channel.close();
            channel = null;
        }

        // other code can go here
    }

    public boolean isSet() {
        synchronized (lock) {
            if (channel == null) {
                return false;
            }
            return channel.isActive();
        }
    }
}
实际上,
lock
对象保护对通道变量的任何访问


编辑以显示未与
频道
交互的其他代码可能位于锁之外的位置。

锁上的外部锁保护所有内容。你不需要第二把锁。当外部锁保持不动时,第二个线程永远无法到达它。

锁上的外部锁保护一切。你不需要第二把锁。当外部锁保持时,第二个线程永远无法到达它。

为什么要锁定新创建的对象?也可以同步整个过程method@ScaryWombat我想在使用之前对创建的对象进行设置。我不应该这样做吗?我不想同步整个方法,因为我为simplisity的sakeIn
setChannel
清理了方法的代码,因为它已经被锁定,所以再次锁定
没有意义。如果
isSet()
真的在
lock
上同步,那么,可怕的袋熊是对的,没有理由在
频道上同步,因为
锁定
上的锁定已经会阻止任何其他代码到达它试图访问
频道
的点。我想你可以通过将
频道
声明为
易失性
,获得同样的效果,而不是在上面同步。你的链接上的人似乎说你必须声明所有实例字段为volatile,但我认为这是不对的——只有那些需要的字段才是。如果有多个线程可能正在访问同一个字段(有些可能是写入),那么它应该是易变的。为什么要锁定新创建的对象?也可以同步整个过程method@ScaryWombat我想在使用之前对创建的对象进行设置。我不应该这样做吗?我不想同步整个方法,因为我为simplisity的sakeIn
setChannel
清理了方法的代码,因为它已经被锁定,所以再次锁定
没有意义。如果
isSet()
真的在
lock
上同步,那么,可怕的袋熊是对的,没有理由在
频道上同步,因为
锁定
上的锁定已经会阻止任何其他代码到达它试图访问
频道
的点。我想你可以通过将
频道
声明为
易失性
,获得同样的效果,而不是在上面同步。你的链接上的人似乎说你必须声明所有实例字段为volatile,但我认为这是不对的——只有那些需要的字段才是。如果您遇到多个线程可能正在访问同一字段的情况(有些线程可能是写的),那么它应该是不稳定的。那么我应该相信谁呢?:)这仅适用于锁定对象为非最终对象的情况。在我的示例中,我锁定了最后一个对象
lock
。我想保护非最终的“通道”对象,那么您的解决方案是否符合条件?如果您将对
通道
对象的每次访问都像我上面所说的那样使用锁进行包装,那么解决方案将起作用。那个家伙说您应该在受保护的对象上进行同步“为了RAM同步”。那么我应该相信谁呢?:)这仅适用于锁定对象为非最终对象的情况。在我的示例中,我锁定了最后一个对象
lock
。我想保护非最终的“通道”对象,那么您的解决方案是否符合条件?如果您将对
通道
对象的每次访问都像我上面所说的那样使用锁进行包装,那么解决方案将起作用。那个家伙说您应该在受保护的对象上进行同步“为了RAM同步”。一个锁真的足够了吗?那个家伙说你应该在受保护的对象上同步“为了RAM同步”。一把锁就够了吗?