1

在这里,我采用了一个字符串锁来进行测试,以了解两个线程的实际流如何表现,但它给了我不可预测的输出。

这是代码...

public class SyncCall {static SyncTesting sync1 = new SyncTesting();

    static Runnable r1=new Runnable() {
    public void run() {
        try {
            sync1.s=new String("15");
            Thread.currentThread().setName("Thread1");
            sync1.testme();
          //  Thread.sleep(1000);

            System.out.println(Thread.currentThread().getName());
            System.out.println("sync1");
        } catch (Exception ex) {
            Logger.getLogger(SyncCall.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
};   
    static  Runnable r2=new Runnable() {
    public void run() {
        try {     
            sync1.s=new String("17");
             Thread.currentThread().setName("Thread2");
            sync1.testme();
            //Thread.sleep(1000);

            System.out.println(Thread.currentThread().getName());
            System.out.println("sync2");
        } catch (Exception ex) {
            Logger.getLogger(SyncCall.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
};
public static void main(String args[]){
    Thread th1=new Thread(r1);
    Thread th2=new Thread(r2);
    th1.start();
    th2.start();
}

}

public class SyncTesting {String s=new String("abc");
//final Object s=new Object();
public void testme(){
    synchronized(s){
        try {
            System.out.println("Hello");
            System.out.println(s);
           // s=new String("18");
            Thread.sleep(1000);
            System.out.println("Hello after sleep" +Thread.currentThread().getName());
        } catch (Exception ex) {
            Logger.getLogger(SyncTesting.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

}

我得到的输出就像有时......

Hello 17 Hello 17 在 sleepThread1 之后 Hello Thread1 sync1 在 sleepThread2 之后 Hello Thread2 sync2

而有时...

Hello 15 Hello 15 在 sleepThread2 之后的 Hello Thread2 sync2 在 sleepThread1 之后的 Hello Thread1 sync1

我知道我得到不同的输出是因为 String 对象作为同步中的锁,但我想知道为什么两个线程给出相同的字符串值而另一个线程更改该字符串值。

4

4 回答 4

1

这有很多错误,很难知道从哪里开始。

  1. 您实际上synchronize并没有在不同线程之间进行任何操作。您正在调用testme它们永远不会交互的完全不同的对象。

  2. 调用new String("abc")是对象的不正确使用。调用保证实例不会相同,即使对于相同的数据也是如此new。.StringString a = new String("abc"); String b = new String("abc"); a == b is false

  3. 您必须在所有块中使用相同锁定对象的完全相同的实例synchronized,这应该很明显,否则它应该如何知道要阻止访问什么?

  4. 必须标记共享数据,volatile否则线程可能会或可能不会看到数据更新。

  5. 学习在AtmoicInteger此类需要安全共享数据的情况下使用。

  6. 不要Threads像这样手动开始学习如何使用ExecutorService.

于 2013-09-19T14:15:40.910 回答
1

打印相同的 S 值 (17) 时

T1 --> sets S=15 --->enters Syn Block --> prints Hello --> prints S (T2 has set S=17)
T2 -------------> sets S=17 --->enters Syn Block --> print Hello --> prints S

打印相同的 S 值 (15) 时

T1 ------------> sets S=15 --->enters Syn Block --> prints Hello --> prints S 
T2 --> sets S=17 ---> enters Syn Block --> print Hello --> prints S (S=15 set before T2 prints S)

打印差异值时

T1 --> sets S=15 --->enters Syn Block --> prints Hello --> prints S 
T2 -----------------------------------------------------------------> sets S=17 --->enters Syn Block --> print Hello --> prints S

这里的问题是您更改了锁定对象本身。所以两个线程可以执行相同的代码块,即使它的同步

于 2013-09-19T14:05:21.477 回答
0

时间线选项 1 - 可以按任意顺序发生(15 优先或 17 优先)

  • r1:将 s 设置为 15
  • r2:将 s 设置为 17
  • r1:使用 17 进入锁
  • r2: 使用 17 进入锁被阻止
  • r1:退出锁
  • r2:进入锁
  • r2:退出锁

时间线选项 2:

  • r1:将 s 设置为 15
  • r1:使用 15 进入锁
  • r2:将 s 设置为 17
  • r2:使用 17 进入锁(未阻塞,因为锁在不同的值上)
  • r1:退出锁
  • r2:退出锁

这里的问题是您更改了要锁定的引用,因此每个线程都可以在进入时锁定不同的值。同样对于多线程来说,仅仅因为一个线程设置了一个值并不意味着如果另一个线程能够更改它,它将继续看到该值。

于 2013-09-19T13:22:27.587 回答
0

我猜如果第二个线程在第一个线程使用它之前更改了值,它保持更改,否则第二个线程首先设置值,第一个线程更改它

于 2013-09-19T12:59:37.807 回答