Java线程共享对象同步问题
我遇到了 Synchronized 的问题,其行为不符合我的预期,我也尝试使用 volatile 关键字:
共享对象:
public class ThreadValue {
private String caller;
private String value;
public ThreadValue( String caller, String value ) {
this.value = value;
this.caller = caller;
}
public synchronized String getValue() {
return this.caller + " " + this.value;
}
public synchronized void setValue( String caller, String value ) {
this.caller = caller;
this.value = value;
}
}
线程 1:
class CongoThread implements Runnable {
private ThreadValue v;
public CongoThread(ThreadValue v) {
this.v = v;
}
public void run() {
for (int i = 0; i 10; i++) {
v.setValue( "congo", "cool" );
v.getValue();
}
}
}
线程 2:
class LibyaThread implements Runnable {
private ThreadValue v;
public LibyaThread(ThreadValue v) {
this.v = v;
}
public void run() {
for (int i = 0; i 10; i++) {
v.setValue( "libya", "awesome" );
System.out.println("In Libya Thread " + v.getValue() );
}
}
}
调用类:
class TwoThreadsTest {
public static void main (String args[]) {
ThreadValue v = new ThreadValue("", "");
Thread congo = new Thread( new CongoThread( v ) );
Thread libya = new Thread( new LibyaThread( v ) );
libya.start();
congo.start();
}
}
偶尔我会得到“在利比亚线程刚果很酷” 这绝对不应该发生。 我只期望: “利比亚主题利比亚真棒” “在刚果线程刚果很酷”
我不希望它们混合在一起。
I'm having issues with Synchronized not behaving the way i expect, i tried using volatile keyword also:
Shared Object:
public class ThreadValue {
private String caller;
private String value;
public ThreadValue( String caller, String value ) {
this.value = value;
this.caller = caller;
}
public synchronized String getValue() {
return this.caller + " " + this.value;
}
public synchronized void setValue( String caller, String value ) {
this.caller = caller;
this.value = value;
}
}
Thread 1:
class CongoThread implements Runnable {
private ThreadValue v;
public CongoThread(ThreadValue v) {
this.v = v;
}
public void run() {
for (int i = 0; i 10; i++) {
v.setValue( "congo", "cool" );
v.getValue();
}
}
}
Thread 2:
class LibyaThread implements Runnable {
private ThreadValue v;
public LibyaThread(ThreadValue v) {
this.v = v;
}
public void run() {
for (int i = 0; i 10; i++) {
v.setValue( "libya", "awesome" );
System.out.println("In Libya Thread " + v.getValue() );
}
}
}
Calling Class:
class TwoThreadsTest {
public static void main (String args[]) {
ThreadValue v = new ThreadValue("", "");
Thread congo = new Thread( new CongoThread( v ) );
Thread libya = new Thread( new LibyaThread( v ) );
libya.start();
congo.start();
}
}
Occasionally i get "In Libya Thread congo cool"
which should never happen. I expect only:
"In Libya Thread libya awesome"
"In Congo Thread congo cool"
I dont expect them to be mixed.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
为什么他们不混合呢? 尽管每个单独的调用都是同步的,但没有什么可以阻止一个线程调用 v.setValue,然后另一个线程调用 setValue,然后第一个线程调用 getValue()。 我相信这就是正在发生的事情。 您可以通过使用来避免这种情况:
这样,在每次迭代时,它都会确保它调用
setValue
和getValue
而无需另一个线程调用同时设置Value。
诚然,这不是一个理想的设计 - 但我猜这个演示比其他任何东西都更能理解同步:)
Why would they not be mixed? Although each individual call is synchronized, there's nothing to stop one thread from calling v.setValue, then the other thread calling setValue, then the first thread calling getValue(). I believe that's what's happening. You could avoid this by using:
That way, on each iteration it makes sure that it calls
setValue
andgetValue
without another thread callingsetValue
in the meantime.It's not an ideal design, admittedly - but I'm guessing this demonstration is more to understand synchronization than anything else :)
发生的情况如下:
为了解决此问题,您需要有 1 个锁对象来保护两个线程的 get/set 函数调用。 做到这一点的最佳方法是创建一个额外的同步方法来执行设置和获取。 但有时这是不可取的。 在这种情况下,给两个线程一个锁对象。 这只是一个普通的对象。 然后他们在同步块中使用它。
每个线程的实现如下所示,注意它们需要具有完全相同的对象!
What happens is the follwing:
In order to fix this you need to have 1 lock object that guards the get/set functions call for both threads. The best way to do this, is to make an extra synchronized method that does both the set and the get. However sometimes that isn't desirable. In that case give both threads a lock object. Which is just a plain object. Which they then use in a synchronized block.
Implementation of each thread would like like the following, note that they need to have precisely the same object!
问题是,利比亚线程的 v.getValue() 可能在刚果线程调用 v.setValue() 之后立即被调用,从而导致您混淆。
解决方案是让一个线程阻止获取和设置值,否则您将继续遇到该问题。 您必须在 setter 内部调用 getter 或使用 wait/notify 让另一个线程等待,直到一个线程设置并获取该值。
The problem is, it's possible that the v.getValue() for the Libya thread is being called right after the Congo thread has called v.setValue(), thus resulting in your mix up.
The solution is to have a thread block BOTH the get and set values, otherwise you're going to continue to have that problem. You'll have to call the getter inside of the setter or use a wait/notify to have the other thread wait until the one thread has both set and gotten the value.