使用同步方法的问题

Issues on using synchronized method

我试图了解同步,但在尝试实现它时,我得到了一个模棱两可的结果,在尝试实现同步时,请看一下。

通过观察输出,很明显两个线程能够同时访问同步块。指导我哪里错了。

输出:

Display class show method called by- Thread-0
Display class show method called by- Thread-0
Display class show method called by- Thread-0
Display class show method called by- Thread-0
Display class show method called by- Thread-0
Display class show method called by- Thread-0
Display class show method called by- Thread-0
Display class show method called by- Thread-1
Display class show method called by- Thread-1
Display class show method called by- Thread-1
Display class show method called by- Thread-1
Display class show method called by- Thread-1
Display class show method called by- Thread-1
Display class show method called by- Thread-1
Display class show method called by- Thread-1
Display class show method called by- Thread-1
Display class show method called by- Thread-1
Display class show method called by- Thread-0
Display class show method called by- Thread-0
Display class show method called by- Thread-0

计划:

package com.Whosebug.Doubts3;

public class Dbts5 {
public static void main(String[] args) {

    Display d1= new Display();
    MyThreads th1= new MyThreads(d1, "Thread1");

    th1.start();

    MyThreads th2= new MyThreads(d1, "Thread2");

    th2.start();




}
}

class MyThreads extends Thread{


Display d;
String name;


@Override
public void run() {
    super.run();
    for (int i = 0; i < 10; i++) {
        d.show();   
    }



}

public MyThreads() {}

MyThreads(Display d, String name){
    this.d=d;
    this.name=name;
}


}

class Display{

synchronized void show(){
    System.out.println("Display class show method called by- "+Thread.currentThread().getName());
    try {
        Thread.currentThread().sleep(300);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}
}

(已编辑) 预期输出:

Display class show method called by- Thread-0
Display class show method called by- Thread-0
Display class show method called by- Thread-0
.
.
.
Display class show method called by- Thread-1
Display class show method called by- Thread-1
Display class show method called by- Thread-1

By obesrving the output, it is clear that two threads are able to access the synchronized block simultaneously.

不,绝对没有证据表明这一点。让我们考虑以下输出:

Display class show method called by- Thread-0
Display class show method called by- Thread-1

这里:

  • Thread-0调用show(),进入synchronized块,打印消息,退出show()(离开synchronized 块)。
  • Thread-1调用show(),进入synchronized块,打印消息,退出show()(离开synchronized 块)。

等等。

如果您想看到线程相互阻塞,请将 synchronized 放在循环周围:

synchronized(d) {
    for (int i = 0; i < 10; i++) {
        d.show();   
    }
}

你的同步块没有被并发访问。

您观察到的是:

  • Thread-0 进出 7 次
  • Thread-1 进出 10 次
  • Thread-0 进出 3 次

如果添加一些跟踪,您会发现 show 在退出之前从未输入过两次:

synchronized void show(){
    System.out.println(Thread.currentThread().getName() + " In");
    // do show
    System.out.println(Thread.currentThread().getName() + " Out");
}

你会看到:

Thread-0 In
Display class show method called by- Thread-0
Thread-0 Out
// ...
Thread-1 In
Display class show method called by- Thread-1
Thread-1 Out
// ...
Thread-0 In
Display class show method called by- Thread-0
Thread-0 Out

如果你想让线程在释放锁之前调用shown次,那么你应该在for-loop:

周围使用synchronized
@Override
public void run() {
    showSeveralTimes(10);
}

Display中:

synchronized void showSeveralTimes(int n) {
    for(int i = 0 ; i < n ; ++i) {
        show();
    }
}

引用自 Oracle tutorial:

  • First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
  • Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.

所以 Thread-n 运行,returns,Thread-n 运行,returns,无限循环(在这种情况下为 10)