繁体   English   中英

从非同步方法访问的同步对象

[英]Synchronized objects accessed from unsynchronized methods

假设我有一个类,其中有一个StringBuffer声明为成员变量。 两个线程试图像下面那样操纵对象

public class SomeService {

    private StringBuffer sb = new StringBuffer();

    public void printName(String name) {
        sb.append(name);
        System.out.println(sb);
    }
}

public class StringBufferSynchronizationTest implements Runnable {

    private SomeService service = new SomeService();

    public StringBufferSynchronizationTest() {

        Thread thread = new Thread(this);
        thread.start();
    }

    public static void main(String[] args) {

        new StringBufferSynchronizationTest().service.printName("oops");
    }

    @Override
    public void run() {
        service.printName("java");
    }
}

我得到了这个输出

oopsjava
oopsjava

我以为我会得到

oops
oopsjava

作为输出。 当我同步printName方法时,我得到了第二个输出。

所以我明白,即使我使用同步类,我也必须同步使用synchronized类的块/方法。 我对吗?

StringBuffer保证只有一个线程可以输入append或同一实例的任何其他方法。 但这就是全部,没有更多的保证。

是的,StringBuffer是同步的,如果你想要预期的结果,也同步函数printName。 sb.append(name);之间可以发生上下文切换sb.append(name); System.out.println(sb); 特别是它与缓慢的IO有关。

public synchronized void printName(String name) {
    sb.append(name);
    System.out.println(sb);
}

这取决于你想要完成什么。

我们来看看printName

public void printName(String name) {
    sb.append(name);
    System.out.println(sb);
}

由于sb在synchronized中, sb.append(name)只有1个线程在对象上运行可变状态。 这可以防止在您的示例中使用值的字符串

oojavaps
ojopsava

等等。 但是,由于您的printName方法未同步,因此无法保证在2个线程中调用printName中的2个方法的顺序。

理解它的最简单方法可能是提出导致输出的执行顺序

oopsjava
oopsjava

最初sb是空字符串

假设主线程执行sb.append(name) ,将sb留给oops ,但是在它执行println之前它被抢占了

构造器线程接管并执行整个方法,首先追加javasb获得oopsjavasb ,然后打印输出,以获得

oopsjava

然后主线程执行,打印sb得到

oopsjava

我有一个输出示例,这是不正确的,@ Cruncher在评论中指出了这一点,我删除了它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM