繁体   English   中英

Java线程共享对象同步问题

[英]Java Thread Shared Object Synchronization Issue

我遇到的问题是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();

    }
}

偶尔我会得到“在利比亚线程刚果酷”,这应该永远不会发生。 我只期望:“在利比亚线程利比亚真棒”“在刚果线程刚果酷”

我不希望他们混在一起。

为什么他们不会混在一起? 虽然每个单独的调用都是同步的,但是没有什么可以阻止一个线程调用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没有另一个调用setValue线程。

诚然,这不是一个理想的设计 - 但我猜这个演示更能理解同步而不是其他任何东西:)

接下来会发生什么:

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

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

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

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() );
            }
        }
    }
}

问题是,在刚刚线程调用v.setValue()之后,可能正在调用Libya线程的v.getValue(),从而导致混淆。

解决方案是让一个线程块同时获取get和set值,否则你将继续遇到这个问题。 您必须在setter中调用getter或使用wait / notify让另一个线程等待,直到一个线程同时设置并获得该值。

暂无
暂无

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

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