在java中测试同步

在java中测试同步,java,multithreading,synchronize,Java,Multithreading,Synchronize,这里我拿了一个字符串锁进行测试,以了解两个线程的实际流量 行为,但它给我不可预知的输出 这是代码 public class SyncCall {static SyncTesting sync1 = new SyncTesting(); static Runnable r1=new Runnable() { public void run() { try { sync1.s=new String("15"); Thr

这里我拿了一个字符串锁进行测试,以了解两个线程的实际流量 行为,但它给我不可预知的输出

这是代码

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

}

我得到的输出有时像

你好 17 你好 17 你好,在睡后1 螺纹1 同步1 睡后你好2 螺纹2 同步2

有时候

你好 15 你好 15 睡后你好2 螺纹2 同步2 你好,在睡后1 螺纹1 同步1

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

我猜如果第二个线程在第一个线程使用它之前更改该值,它将保持更改状态,否则第二个线程将首先设置该值,而第一个线程更改该值。时间轴选项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输入lock(未被阻止,因为lock的值不同)
  • r1:出口锁
  • r2:出口锁
这里的问题是,您已经更改了要锁定的引用,因此每个线程都可以在条目上锁定不同的值。对于多线程,仅仅因为一个线程设置了一个值,并不意味着如果另一个线程能够更改它,它将继续看到该值。

当打印相同的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
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)
打印相同的S值(15)时

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
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
这里的问题是更改锁对象本身。因此,两个线程可以执行相同的代码块,即使它的sync

有太多错误,以至于很难知道从哪里开始。
  • 实际上,您从未在不同线程之间对任何内容进行
    同步。您正在对完全不同的对象调用
    testme
    ,它们永远不会交互

  • 调用
    新字符串(“abc”)
    是不正确的对象用法。在
    String
    上调用
    new
    可以保证实例将相同,即使对于相同的数据也是如此<代码>字符串a=新字符串(“abc”);字符串b=新字符串(“abc”);a==b为假

  • 您必须在所有
    synchronized
    块中使用同一锁定对象的完全相同的实例,这应该是非常明显的,否则它怎么知道要阻止访问什么

  • 共享数据必须标记为
    volatile
    ,否则线程可能会或可能不会看到数据的更新

  • 学习在您希望安全共享数据的情况下使用
    AtmoicInteger

  • 不要像这样手动启动
    线程
    了解如何使用
    执行器服务