Java线程共享对象同步问题

发布于 2024-07-26 23:17:49 字数 1559 浏览 8 评论 0原文

我遇到了 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦罢 2024-08-02 23:17:49

为什么他们不混合呢? 尽管每个单独的调用都是同步的,但没有什么可以阻止一个线程调用 v.setValue,然后另一个线程调用 setValue,然后第一个线程调用 getValue()。 我相信这就是正在发生的事情。 您可以通过使用来避免这种情况:

public void run() {
    for (int i = 0; i  10; i++) {
       synchronized (v) {
           v.setValue( "libya", "awesome" );
           System.out.println("In Libya Thread " + v.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:

public void run() {
    for (int i = 0; i  10; i++) {
       synchronized (v) {
           v.setValue( "libya", "awesome" );
           System.out.println("In Libya Thread " + v.getValue() );
       }
    }
}

That way, on each iteration it makes sure that it calls setValue and getValue without another thread calling setValue in the meantime.

It's not an ideal design, admittedly - but I'm guessing this demonstration is more to understand synchronization than anything else :)

墨落成白 2024-08-02 23:17:49

发生的情况如下:

  1. 线程 1 设置值
  2. 线程 2 设置值
  3. 线程 1 读取线程 2 设置的值。

为了解决此问题,您需要有 1 个锁对象来保护两个线程的 get/set 函数调用。 做到这一点的最佳方法是创建一个额外的同步方法来执行设置和获取。 但有时这是不可取的。 在这种情况下,给两个线程一个锁对象。 这只是一个普通的对象。 然后他们在同步块中使用它。

每个线程的实现如下所示,注意它们需要具有完全相同的对象!

Object lockObject = new Object();
Thread t1 = new CongroThread(v, lockObject);
Thread t2 = new LibyaThread(v, lockObject);

...

class CongoThread implements Runnable {
    private ThreadValue v;
    private Object lockObject;

    public CongoThread(ThreadValue v, Object lockObject) {
    this.v = v;
    this.lockObject = lockObject,
    }
    public void run() {
        for (int i = 0; i < 10; i++) {
            synchronized(lockObject)
            {
                v.setValue( "libya", "awesome" );
                System.out.println("In Libya Thread " + v.getValue() );
            }
        }
    }
}

What happens is the follwing:

  1. Thread 1 sets the value
  2. Thread 2 sets the value
  3. Thread 1 reads the value set by thread 2.

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!

Object lockObject = new Object();
Thread t1 = new CongroThread(v, lockObject);
Thread t2 = new LibyaThread(v, lockObject);

...

class CongoThread implements Runnable {
    private ThreadValue v;
    private Object lockObject;

    public CongoThread(ThreadValue v, Object lockObject) {
    this.v = v;
    this.lockObject = lockObject,
    }
    public void run() {
        for (int i = 0; i < 10; i++) {
            synchronized(lockObject)
            {
                v.setValue( "libya", "awesome" );
                System.out.println("In Libya Thread " + v.getValue() );
            }
        }
    }
}
悲歌长辞 2024-08-02 23:17:49

问题是,利比亚线程的 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文