Java synchronized锁对象和锁非静态成员变量的实验

关于Java synchronized,网上博文对主要概念都解释的很清楚,但对锁对象和锁对象的非静态成员变量的区别,或者没有提到,或者讲述的不是特别清晰、深刻。

根据本人的理解和实验效果,我认为Java synchronized的主要用法分三种:

  • 锁静态函数或类.class(即所谓的类锁)
  • 锁对象/锁函数(本文简称对象锁)
  • 锁对象的非静态成员变量(本文简称变量锁)

本文对第1种用法不做讨论,仅讨论后两种用法的区别。

实验环境:win10 + intelliJ

1. 对象锁与变量锁分开使用,并不能实现同步保护

public class JavaSync {
    public static void main(String[] args) {
        SyncContent syncContent = new SyncContent("JavaSync");

        ThreadA a = new ThreadA(syncContent);
        a.setName("A");
        a.start();

        ThreadB b = new ThreadB(syncContent);
        b.setName("B");
        b.start();

        ThreadC c = new ThreadC(syncContent);
        c.setName("C");
        c.start();
    }
}

class SyncContent {
    String content = new String();

    public SyncContent(String content){
        this.content = content;
    }

    synchronized public void syncFunc(String str){
        try {
            System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " enter: " + System.currentTimeMillis());
            System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " content old: " + content);
            content = str;
            System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " content new: " + content);
            Thread.sleep(2000);
            System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " content final: " + content);
            System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " exit: " + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void syncThis(String str){
        synchronized(this) {
            try {
                System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " enter: " + System.currentTimeMillis());
                System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content old: " + content);
                content = str;
                System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content new: " + content);
                Thread.sleep(2000);
                System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content final: " + content);
                System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " exit: " + System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void syncVariable(String str) {
        synchronized(content) {
            System.out.println("syncVariable.Thread: " + Thread.currentThread().getName() + " enter: " + System.currentTimeMillis());
            System.out.println("syncVariable.Thread: " + Thread.currentThread().getName() + " content old: " + content);
            content = str;
            System.out.println("syncVariable.Thread: " + Thread.currentThread().getName() + " content new: " + content);
            System.out.println("syncVariable.Thread: " + Thread.currentThread().getName() + " exit: " + System.currentTimeMillis());
        }
    }
}

class ThreadA extends Thread {
    private SyncContent syncContent;
    private String me = "ThreadA";

    public ThreadA(SyncContent syncContent) {
        super();
        this.syncContent = syncContent;
    }

    @Override
    public void run() {
        syncContent.syncThis(me);
    }
}


class ThreadB extends Thread {
    private SyncContent syncContent;
    private String me = "ThreadB";

    public ThreadB(SyncContent syncContent) {
        super();
        this.syncContent = syncContent;
    }

    @Override
    public void run() {
        syncContent.syncFunc(me);
    }
}

class ThreadC extends Thread {
    private SyncContent syncContent;
    private String me = "ThreadC";

    public ThreadC(SyncContent syncContent) {
        super();
        this.syncContent = syncContent;
    }

    @Override
    public void run() {
        syncContent.syncVariable(me);
    }
}

 Log如下:

syncThis.Thread: A enter: 1542010389797
syncThis.Thread: A content old: JavaSync
syncThis.Thread: A content new: ThreadA
syncVariable.Thread: C enter: 1542010389798
syncVariable.Thread: C content old: ThreadA
syncVariable.Thread: C content new: ThreadC
syncVariable.Thread: C exit: 1542010389798
syncThis.Thread: A content final: ThreadC
syncThis.Thread: A exit: 1542010391798
syncFunc.Thread: B enter: 1542010391798
syncFunc.Thread: B content old: ThreadC
syncFunc.Thread: B content new: ThreadB
syncFunc.Thread: B content final: ThreadB
syncFunc.Thread: B exit: 1542010393799

从上述log可见:

  • synchronized(this) 与 synchronized Function 的功能一致,都是锁对象。
  • synchronized(this)并不会与synchronized(content)形成同步,两者并没有包含关系。即使content是this里包含的成员,但对于synchronized()来讲,是两个不同的输入对象或者说参数,二者不会同步。

2. 对象锁与变量锁嵌套使用,也不能实现同步保护

把syncThis()和syncFunc()函数里嵌套synchronized (content): 

public void syncThis(String str){
    synchronized(this) {
        try {
            System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " enter: " + System.currentTimeMillis());
            System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content old: " + content);
            synchronized (content) {
                content = str;
                System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content new: " + content);
                Thread.sleep(2000);
            }
            System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content final: " + content);
            System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " exit: " + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 Log如下:
syncThis.Thread: A enter: 1542012050428
syncThis.Thread: A content old: JavaSync
syncThis.Thread: A content new: ThreadA
syncVariable.Thread: C enter: 1542012050429
syncVariable.Thread: C content old: ThreadA
syncVariable.Thread: C content new: ThreadC
syncVariable.Thread: C exit: 1542012050429
syncThis.Thread: A content final: ThreadC
syncThis.Thread: A exit: 1542012052428
syncFunc.Thread: B enter: 1542012052428
syncFunc.Thread: B content old: ThreadC
syncFunc.Thread: B content new: ThreadB
syncFunc.Thread: B content final: ThreadB
syncFunc.Thread: B exit: 1542012054429

从上述log可见:即使synchronized(this)中嵌套调用synchronized(content),也没有与单独调用synchronized(content)达到同步的效果。原因待研究。(曾猜测是不是Thread.sleep会释放锁,但把sleep换成一个纯做加减乘除运算的耗时函数后,效果也一样。另外,一些文章也讲了sleep并不会释放线程持有的锁。)

另外实验,如果ThreadB的run()里面改成调用syncVariable(me),是可以与ThreadC形成同步的,这个结果符合预期,不列log。

结论:

  • 锁对象与锁对象的非静态成员变量并不会形成同步,两者并没有包含关系。即使this里包含content成员,但对于synchronized()来讲,是两个不同的输入对象或者说参数,二者不会同步。
  • 如果要对类对象里多个成员变量分别进行同步的,需保持同步参数的一致,即this与this配对(或者this与函数配对),变量与变量各自配对,但不能this与成员变量配对。
  • 锁对象中嵌套调用锁对象的非静态成员变量,也没有达到与单独调用锁对象的非静态成员变量形成同步的效果(原因待研究)。
  • 另外,嵌套用锁,要注意避免死锁;尽量不要嵌套。

 

参考:

https://blog.csdn.net/u013142781/article/details/51697672

https://blog.csdn.net/luoweifu/article/details/46613015

https://blog.csdn.net/u010002184/article/details/72566874

https://bbs.csdn.net/topics/390954513

https://blog.csdn.net/zbuger/article/details/51030772

https://blog.csdn.net/YChenFeng/article/details/77427554

 

Update:

对SyncContent类略做优化调整:给String content添加volatile,更换sleep函数,如下:

class SyncContent {
    volatile String content = new String();

    public SyncContent(String content) {
        this.content = content;
    }

    private double timeConsuming() {
        double a, b, c;
        double sum = 0;
        for (int i = 1; i < 2000000; i++) {
            a = i + sum / ( i * 19);
            b = a / 17;
            c = b * 23;
            sum += (b + c - a) / (a + i);
        }
        return sum;
    }

    synchronized public void syncFunc(String str) {
        System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " enter: " + System.currentTimeMillis());
        synchronized (content) {
            System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " content old: " + content);
            content = str;
            System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " content new: " + content);
            //Thread.sleep(2000);  // InterruptedException
            System.out.println("syncFunc.Thread: dummy result: " + timeConsuming());
            System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " content final: " + content);
        }
        System.out.println("syncFunc.Thread: " + Thread.currentThread().getName() + " exit: " + System.currentTimeMillis());
    }

    public void syncThis(String str) {
        synchronized(this) {
            System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " enter: " + System.currentTimeMillis());
            synchronized (content) {
                System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content old: " + content);
                content = str;
                System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content new: " + content);
                //Thread.sleep(2000);  // InterruptedException
                System.out.println("syncThis.Thread: dummy result: " + timeConsuming());
                System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " content final: " + content);
            }
            System.out.println("syncThis.Thread: " + Thread.currentThread().getName() + " exit: " + System.currentTimeMillis());
        }
    }

    public void syncVariable(String str) {
        synchronized(content) {
            System.out.println("syncVariable.Thread: " + Thread.currentThread().getName() + " enter: " + System.currentTimeMillis());
            System.out.println("syncVariable.Thread: " + Thread.currentThread().getName() + " content old: " + content);
            content = str;
            System.out.println("syncVariable.Thread: " + Thread.currentThread().getName() + " content new: " + content);
            System.out.println("syncVariable.Thread: " + Thread.currentThread().getName() + " exit: " + System.currentTimeMillis());
        }
    }
}

Log如下:

syncThis.Thread: A enter: 1542076529822
syncThis.Thread: A content old: JavaSync
syncThis.Thread: A content new: ThreadA
syncVariable.Thread: C enter: 1542076529823
syncVariable.Thread: C content old: ThreadA
syncVariable.Thread: C content new: ThreadC
syncVariable.Thread: C exit: 1542076529824
syncThis.Thread: dummy result: 411764.5149938948
syncThis.Thread: A content final: ThreadC
syncThis.Thread: A exit: 1542076529862
syncFunc.Thread: B enter: 1542076529862
syncFunc.Thread: B content old: ThreadC
syncFunc.Thread: B content new: ThreadB
syncFunc.Thread: dummy result: 411764.5149938948
syncFunc.Thread: B content final: ThreadB
syncFunc.Thread: B exit: 1542076529897

嵌套synchronized()调用,仍然没有起到同步保护的作用。

反编译SyncContent.class,发现syncThis()中存在两层monitorenter,putfield content也在monitorenter内层,但从log看,并没有真正同步。

$ javap -c SyncContent.class
Compiled from "JavaSync.java"
class SyncContent {
  volatile java.lang.String content;

  public SyncContent(java.lang.String);
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: new           #2                  // class java/lang/String
       8: dup
       9: invokespecial #3                  // Method java/lang/String."<init>":()V
      12: putfield      #4                  // Field content:Ljava/lang/String;
      15: aload_0
      16: aload_1
      17: putfield      #4                  // Field content:Ljava/lang/String;
      20: return

  public synchronized void syncFunc(java.lang.String);
    Code:
       0: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: new           #11                 // class java/lang/StringBuilder
       6: dup
       7: invokespecial #12                 // Method java/lang/StringBuilder."<init>":()V
      10: ldc           #13                 // String syncFunc.Thread:
      12: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      15: invokestatic  #15                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
      18: invokevirtual #16                 // Method java/lang/Thread.getName:()Ljava/lang/String;
      21: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      24: ldc           #17                 // String  enter:
      26: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      29: invokestatic  #18                 // Method java/lang/System.currentTimeMillis:()J
      32: invokevirtual #19                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
      35: invokevirtual #20                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      38: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      41: aload_0
      42: getfield      #4                  // Field content:Ljava/lang/String;
      45: dup
      46: astore_2
      47: monitorenter
      48: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
      51: new           #11                 // class java/lang/StringBuilder
      54: dup
      55: invokespecial #12                 // Method java/lang/StringBuilder."<init>":()V
      58: ldc           #13                 // String syncFunc.Thread:
      60: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      63: invokestatic  #15                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
      66: invokevirtual #16                 // Method java/lang/Thread.getName:()Ljava/lang/String;
      69: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      72: ldc           #22                 // String  content old:
      74: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      77: aload_0
      78: getfield      #4                  // Field content:Ljava/lang/String;
      81: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      84: invokevirtual #20                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      87: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      90: aload_0
      91: aload_1
      92: putfield      #4                  // Field content:Ljava/lang/String;
      95: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
      98: new           #11                 // class java/lang/StringBuilder
     101: dup
     102: invokespecial #12                 // Method java/lang/StringBuilder."<init>":()V
     105: ldc           #13                 // String syncFunc.Thread:
     107: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     110: invokestatic  #15                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
     113: invokevirtual #16                 // Method java/lang/Thread.getName:()Ljava/lang/String;
     116: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     119: ldc           #23                 // String  content new:
     121: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     124: aload_0
     125: getfield      #4                  // Field content:Ljava/lang/String;
     128: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     131: invokevirtual #20                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     134: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     137: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
     140: new           #11                 // class java/lang/StringBuilder
     143: dup
     144: invokespecial #12                 // Method java/lang/StringBuilder."<init>":()V
     147: ldc           #24                 // String syncFunc.Thread: dummy result:
     149: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     152: aload_0
     153: invokespecial #25                 // Method timeConsuming:()D
     156: invokevirtual #26                 // Method java/lang/StringBuilder.append:(D)Ljava/lang/StringBuilder;
     159: invokevirtual #20                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     162: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     165: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
     168: new           #11                 // class java/lang/StringBuilder
     171: dup
     172: invokespecial #12                 // Method java/lang/StringBuilder."<init>":()V
     175: ldc           #13                 // String syncFunc.Thread:
     177: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     180: invokestatic  #15                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
     183: invokevirtual #16                 // Method java/lang/Thread.getName:()Ljava/lang/String;
     186: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     189: ldc           #27                 // String  content final:
     191: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     194: aload_0
     195: getfield      #4                  // Field content:Ljava/lang/String;
     198: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     201: invokevirtual #20                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     204: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     207: aload_2
     208: monitorexit
     209: goto          217
     212: astore_3
     213: aload_2
     214: monitorexit
     215: aload_3
     216: athrow
     217: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
     220: new           #11                 // class java/lang/StringBuilder
     223: dup
     224: invokespecial #12                 // Method java/lang/StringBuilder."<init>":()V
     227: ldc           #13                 // String syncFunc.Thread:
     229: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     232: invokestatic  #15                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
     235: invokevirtual #16                 // Method java/lang/Thread.getName:()Ljava/lang/String;
     238: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     241: ldc           #28                 // String  exit:
     243: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     246: invokestatic  #18                 // Method java/lang/System.currentTimeMillis:()J
     249: invokevirtual #19                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
     252: invokevirtual #20                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     255: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     258: return
    Exception table:
       from    to  target type
          48   209   212   any
         212   215   212   any

  public void syncThis(java.lang.String);
    Code:
       0: aload_0
       1: dup
       2: astore_2
       3: monitorenter
       4: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
       7: new           #11                 // class java/lang/StringBuilder
      10: dup
      11: invokespecial #12                 // Method java/lang/StringBuilder."<init>":()V
      14: ldc           #29                 // String syncThis.Thread:
      16: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: invokestatic  #15                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
      22: invokevirtual #16                 // Method java/lang/Thread.getName:()Ljava/lang/String;
      25: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      28: ldc           #17                 // String  enter:
      30: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      33: invokestatic  #18                 // Method java/lang/System.currentTimeMillis:()J
      36: invokevirtual #19                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
      39: invokevirtual #20                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      42: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      45: aload_0
      46: getfield      #4                  // Field content:Ljava/lang/String;
      49: dup
      50: astore_3
      51: monitorenter
      52: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
      55: new           #11                 // class java/lang/StringBuilder
      58: dup
      59: invokespecial #12                 // Method java/lang/StringBuilder."<init>":()V
      62: ldc           #29                 // String syncThis.Thread:
      64: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      67: invokestatic  #15                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
      70: invokevirtual #16                 // Method java/lang/Thread.getName:()Ljava/lang/String;
      73: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      76: ldc           #22                 // String  content old:
      78: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      81: aload_0
      82: getfield      #4                  // Field content:Ljava/lang/String;
      85: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      88: invokevirtual #20                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      91: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      94: aload_0
      95: aload_1
      96: putfield      #4                  // Field content:Ljava/lang/String;
      99: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
     102: new           #11                 // class java/lang/StringBuilder
     105: dup
     106: invokespecial #12                 // Method java/lang/StringBuilder."<init>":()V
     109: ldc           #29                 // String syncThis.Thread:
     111: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     114: invokestatic  #15                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
     117: invokevirtual #16                 // Method java/lang/Thread.getName:()Ljava/lang/String;
     120: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     123: ldc           #23                 // String  content new:
     125: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     128: aload_0
     129: getfield      #4                  // Field content:Ljava/lang/String;
     132: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     135: invokevirtual #20                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     138: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     141: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
     144: new           #11                 // class java/lang/StringBuilder
     147: dup
     148: invokespecial #12                 // Method java/lang/StringBuilder."<init>":()V
     151: ldc           #30                 // String syncThis.Thread: dummy result:
     153: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     156: aload_0
     157: invokespecial #25                 // Method timeConsuming:()D
     160: invokevirtual #26                 // Method java/lang/StringBuilder.append:(D)Ljava/lang/StringBuilder;
     163: invokevirtual #20                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     166: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     169: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
     172: new           #11                 // class java/lang/StringBuilder
     175: dup
     176: invokespecial #12                 // Method java/lang/StringBuilder."<init>":()V
     179: ldc           #29                 // String syncThis.Thread:
     181: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     184: invokestatic  #15                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
     187: invokevirtual #16                 // Method java/lang/Thread.getName:()Ljava/lang/String;
     190: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     193: ldc           #27                 // String  content final:
     195: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     198: aload_0
     199: getfield      #4                  // Field content:Ljava/lang/String;
     202: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     205: invokevirtual #20                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     208: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     211: aload_3
     212: monitorexit
     213: goto          223
     216: astore        4
     218: aload_3
     219: monitorexit
     220: aload         4
     222: athrow
     223: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
     226: new           #11                 // class java/lang/StringBuilder
     229: dup
     230: invokespecial #12                 // Method java/lang/StringBuilder."<init>":()V
     233: ldc           #29                 // String syncThis.Thread:
     235: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     238: invokestatic  #15                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
     241: invokevirtual #16                 // Method java/lang/Thread.getName:()Ljava/lang/String;
     244: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     247: ldc           #28                 // String  exit:
     249: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     252: invokestatic  #18                 // Method java/lang/System.currentTimeMillis:()J
     255: invokevirtual #19                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
     258: invokevirtual #20                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     261: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     264: aload_2
     265: monitorexit
     266: goto          276
     269: astore        5
     271: aload_2
     272: monitorexit
     273: aload         5
     275: athrow
     276: return
    Exception table:
       from    to  target type
          52   213   216   any
         216   220   216   any
           4   266   269   any
         269   273   269   any

  public void syncVariable(java.lang.String);
    Code:
       0: aload_0
       1: getfield      #4                  // Field content:Ljava/lang/String;
       4: dup
       5: astore_2
       6: monitorenter
       7: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
      10: new           #11                 // class java/lang/StringBuilder
      13: dup
      14: invokespecial #12                 // Method java/lang/StringBuilder."<init>":()V
      17: ldc           #31                 // String syncVariable.Thread:
      19: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: invokestatic  #15                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
      25: invokevirtual #16                 // Method java/lang/Thread.getName:()Ljava/lang/String;
      28: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      31: ldc           #17                 // String  enter:
      33: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      36: invokestatic  #18                 // Method java/lang/System.currentTimeMillis:()J
      39: invokevirtual #19                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
      42: invokevirtual #20                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      45: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      48: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
      51: new           #11                 // class java/lang/StringBuilder
      54: dup
      55: invokespecial #12                 // Method java/lang/StringBuilder."<init>":()V
      58: ldc           #31                 // String syncVariable.Thread:
      60: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      63: invokestatic  #15                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
      66: invokevirtual #16                 // Method java/lang/Thread.getName:()Ljava/lang/String;
      69: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      72: ldc           #22                 // String  content old:
      74: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      77: aload_0
      78: getfield      #4                  // Field content:Ljava/lang/String;
      81: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      84: invokevirtual #20                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      87: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      90: aload_0
      91: aload_1
      92: putfield      #4                  // Field content:Ljava/lang/String;
      95: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
      98: new           #11                 // class java/lang/StringBuilder
     101: dup
     102: invokespecial #12                 // Method java/lang/StringBuilder."<init>":()V
     105: ldc           #31                 // String syncVariable.Thread:
     107: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     110: invokestatic  #15                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
     113: invokevirtual #16                 // Method java/lang/Thread.getName:()Ljava/lang/String;
     116: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     119: ldc           #23                 // String  content new:
     121: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     124: aload_0
     125: getfield      #4                  // Field content:Ljava/lang/String;
     128: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     131: invokevirtual #20                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     134: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     137: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
     140: new           #11                 // class java/lang/StringBuilder
     143: dup
     144: invokespecial #12                 // Method java/lang/StringBuilder."<init>":()V
     147: ldc           #31                 // String syncVariable.Thread:
     149: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     152: invokestatic  #15                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
     155: invokevirtual #16                 // Method java/lang/Thread.getName:()Ljava/lang/String;
     158: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     161: ldc           #28                 // String  exit:
     163: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     166: invokestatic  #18                 // Method java/lang/System.currentTimeMillis:()J
     169: invokevirtual #19                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
     172: invokevirtual #20                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     175: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     178: aload_2
     179: monitorexit
     180: goto          188
     183: astore_3
     184: aload_2
     185: monitorexit
     186: aload_3
     187: athrow
     188: return
    Exception table:
       from    to  target type
           7   180   183   any
         183   186   183   any
}

该问题待解。

 

更新(原因已找到):

原因:content = str; 这步操作会导致content被赋值给一个新的string对象,所以Thread A 和 Thread C synchronized(content)的对象是不同的,因此没有形成同步保护。

解决办法:

修改content的类型,如把String content 改成 可修改的StringBuilder类型。

或者,另外增加一个不变的对象flag,先同步synchronized(flag),再设置content的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值