[英]how synchronized block works?
我正在學習多線程。 我編寫了一個使用同步程序來使用兩個線程打印10和5表的程序。 雖然同步方法給了我預期的結果,但同步塊卻沒有。 我究竟做錯了什么?
public class SynchronizationDemo {
public static void main(String[] args) {
Thread1 t=new Thread1(10);
Thread1 t1=new Thread1(5);
Thread thread1=new Thread(t);
Thread thread2=new Thread(t1);
thread1.start();
thread2.start();
}
//synchronized method
/*public static synchronized void printTable(int num) {
for (int i = 1; i <= 10; i++) {
System.out.println(num*i);
try {
Thread.sleep(1000);
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
}*/
//synchronized block
public void printTable(int num)
{
synchronized(this){
for (int i = 1; i <= 10; i++) {
System.out.println(num*i);
try {
Thread.sleep(1000);
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
}
}
}
class Thread1 implements Runnable{
int num;
Thread1(int num){
this.num=num;
}
@Override
public void run() {
new SynchronizationDemo().printTable(num);
}
}
代碼輸出:10 5 10 20 30 15 20 40 25 50 60 30 70 35 40 80 90 45 100 50
預期輸出:10 20 30 40 50 60 70 80 90 100 5 10 15 20 25 30 35 40 45 50
兩種方法之間的主要區別在於小而重要的細節。
您的同步塊同步在this
。
您的同步方法(已注釋掉的方法!)是static
方法。 這意味着它正在SynchronizationDemo
類對象上進行SynchronizationDemo
!
但這並不能解釋全部。 另一件事是調用方法的方式。
new SynchronizationDemo().printTable(num);
您正在創建一個新實例,然后在其上調用該方法。
調用靜態方法時,使用哪個實例沒有區別...,因為您正在Class
對象上進行同步。
當您調用實例方法時,實例是不同的, 因此根本沒有相互排斥。 當兩個線程在同一對象上同步時,您只會得到互斥和正確的同步。
您在兩個不同的上下文中使用synchronized
關鍵字。
static synchronized
方法在SynchronizationDemo類級別等待並獲得一個鎖,並且該類只有一個鎖。 因此,該類的所有實例都必須按順序等待該鎖。
synchronized(this)
塊(甚至一個方法)等待並獲取SynchronizationDemo類的對象鎖,每個對象都有一個鎖。 當每個run()方法創建其自己的new SynchronizationDemo()
實例new SynchronizationDemo()
,該方法無需等待其他方法完成即可。
嘗試通過傳遞對象來更改Thread1類。
class Thread1 implements Runnable{
SynchronizationDemo demo;
int num;
Thread1(SynchronizationDemo demo, int num){
this.demo = demo;
this.num = num;
}
@Override
public void run() {
demo.printTable(num);
}
}
現在,您可以將SynchronizationDemo類的相同對象傳遞給兩個線程,如下所示。
public static void main(String[] args) {
SynchronizationDemo demo = new SynchronizationDemo();
Thread1 t=new Thread1(demo, 10);
Thread1 t1=new Thread1(demo, 5);
Thread thread1=new Thread(t);
Thread thread2=new Thread(t1);
thread1.start();
thread2.start();
}
不同之處在於您還將方法更改為不再是static
。
public static synchronized void printTable(int num) { }
等效的同步塊將是
synchronized(SynchronizationDemo.class){
}
因此,即使您有兩個實例,它們仍然使用相同的鎖(因為它們都屬於同一類),而synchronized(this)
鎖定兩個獨立的對象。
您正在線程的run()
方法中創建SynchronizationDemo
對象的新實例。
@Override
public void run() {
new SynchronizationDemo().printTable(num);
}
因此,每個線程都有一個新對象。 因此,在SynchronizationDemo.class
中,如果兩個或多個線程無法訪問同一對象,則同步塊是無用的。 因此,線程工作於不同的對象,並且每個線程都打印出其編號。
如果thread1
比thread2
早工作,請運行兩次或兩次以上的代碼,可以看到不同的輸出。
您應該將static synchronized
關鍵字與printTable
方法一起使用;
public static synchronized void printTable(int num){
//do sth.
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.