![](/img/trans.png)
[英]ConcurrentModificationException with synchronized and unsynchronized methods
[英]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
之前它被抢占了
构造器线程接管并执行整个方法,首先追加java
到sb
获得oopsjava
在sb
,然后打印输出,以获得
oopsjava
然后主线程执行,打印sb
得到
oopsjava
我有一个输出示例,这是不正确的,@ Cruncher在评论中指出了这一点,我删除了它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.