synsynchronized的使用方法:
1、synchronized修飾方法
(1)synchronized修飾非靜態方法: 鎖的是方法的調用者
import java.util.concurrent.TimeUnit;
class Data {
/*synchronized修飾非靜態方法,鎖的是即方法的調用者,即
調用func1方法的對象*/
public synchronized void func1() {
try {
TimeUnit.SECONDS.sleep(3);//休眠3秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("1....");
}
public synchronized void func2() {
System.out.println("2....");
}
}
Test1:
public class Test1 {
public static void main(String[] args) {
Data data=new Data();
new Thread(()->{
data.func1();
}).start();
new Thread(()->{
data.func2();
}).start();
}
}
結果爲:
在上面的代碼中,由於synchronized修飾非靜態方法:,鎖的是方法的調用者;
所以 在本代碼中鎖的是Data類的對象,不同的Data對象,有不同的鎖,但是此代碼中只有一個data對象,第一個線程執行的是data.fun1()方法,第二個線程執行的是data.fun2()方法;
所以當第一個線程執行data.fun1()方法,獲取到data對象的鎖之後,執行data.fun1()方法,第二個線程獲取不到data對象的鎖,所以第二個線程中的方法data.fun2()方法無法執行;只有當第一個線程執行完畢(data.fun1()方法執行完),釋放了data鎖之後,第二個線程才能獲取到data的鎖,執行data.fun2()方法;
Test2:
public class Test1 {
public static void main(String[] args) {
Data data = new Data();
Data data2 = new Data();
new Thread(() -> {
data.func1();
}).start();
new Thread(() -> {
data2.func2();
}).start();
}
}
結果爲:
在上面的代碼中,由於synchronized修飾非靜態方法:,鎖的是方法的調用者;
所以鎖的是Data類的對象,不同的Data對象,有不同的鎖,此代碼中有兩個Data對象:data,data2;
所以當第一個線程獲取到data對象的鎖之後,執行data.fun1()方法;第二個線程執行的是data2.fun2()方法,其與第一個線程獲取的不是同一個對象的鎖,所以也能與第一個線程同時執行,但fun1()方法中,線程休眠了3秒,所以結果先輸出2,再輸出1;
(2)synchronized修飾靜態方法:鎖的是class本身
class Data2 {
/*synchronized修飾靜態方法,鎖的是class本身,本代碼中
鎖的是Data2這個類本身,鎖定的不是對象*/
public synchronized static void func1() {
try {
TimeUnit.SECONDS.sleep(3);//休眠3秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("1....");
}
public synchronized static void func2() {
System.out.println("2....");
}
}
Test1:
public class Test2 {
public static void main(String[] args) {
Data2 data1=new Data2();
new Thread(()->{
data1.func1();
}).start();
new Thread(()->{
data1.func2();
}).start();
}
}
結果爲:
上面的代碼中,由於synchronized修飾靜態方,:鎖的是class本身;
所以第一個線程執行data1.func1()方法,獲取到了Data類的鎖;而第二個線程中執行的方法是data1.func2()方法,但因爲第一個線程已經獲取了Data類的鎖,所以無法獲取鎖,只有當第一個線程執行完data1.func1()方法之後,釋放了Data類的鎖,第二個線程才能運行執行獲取到Data類的鎖,執行data1.func2()方法;
Test2:
public class Test2 {
public static void main(String[] args) {
Data2 data1=new Data2();
Data2 data2=new Data2();
new Thread(()->{
data1.func1();
}).start();
new Thread(()->{
data2.func2();
}).start();
}
}
結果爲:
在上面的代碼中,synchronized修飾的是靜態方法(static修飾的方法),則鎖的是class本身;
所以在本代碼中,鎖的是Data.class這個類對象,由於一個類只有一個class對象,所以不管該類有幾個實例對象,當一個線程獲取該類的鎖之後,其他線程就無法獲取該類的鎖了,只有當上一個線程釋放了鎖之後,其他線程才能獲取這個類的鎖,執行方法
2、synchronized修飾代碼塊
(1)synchronized(類對象)即synchronized(class):鎖的是同一個類
class Data3{
public void func1(Integer num) {
synchronized (Data3.class) {//鎖的是同一個類
System.out.println("start....");
try {
TimeUnit.SECONDS.sleep(3);//休眠3秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end....");
}
}
}
Test:
import java.util.concurrent.TimeUnit;
public class Test3 {
public static void main(String[] args) {
Data3 data=new Data3();
for(int i=0;i<5;i++){
Integer num=Integer.valueOf(i);
new Thread(()->{
data.func1(num);
}).start();
}
}
}
結果爲:
由於代碼中 synchronized (Data3.class)鎖的是Data3.class這個類對象,
所以對於代碼中的那5個線程,每次執行fun1(num)方法時,只有當一個線程獲取到Data3.class這個類的鎖之後,執行完func1(num)方法,釋放了Data3.class的鎖之後,才能執行下一個線程;
(2)synchronized(對象):鎖的是同一個對象
class Data3{
public void func2(Integer num) {
synchronized (num) {//鎖的是同一個num對象
System.out.println(num+"start....");
try {
TimeUnit.SECONDS.sleep(3);//休眠3秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end....");
}
}
}
Test:
import java.util.concurrent.TimeUnit;
public class Test3 {
public static void main(String[] args) {
Data3 data=new Data3();
for(int i=0;i<5;i++){
Integer num=Integer.valueOf(1);//同一個num對象
new Thread(()->{
data.func2(num);
}).start();
}
}
}
結果爲:
由於代碼中 synchronized (num)鎖的是num這個實例對象;
又由於 Integer num=Integer.valueOf(1),不管創建多少次,都是對應的堆中的同一個對象,
所以對於代碼中的那5個線程,每次執行fun2(num)方法時,鎖的時同一個num,只有當一個線程獲取到num這個對象的鎖之後,執行完func2(num)方法,釋放了num的鎖之後,才能執行下一個線程;
Test3:
public class Test3 {
public static void main(String[] args) {
Data3 data=new Data3();
for(int i=0;i<5;i++){
Integer num=Integer.valueOf(i);//不同的num對象
new Thread(()->{
data.func2(num);
}).start();
}
}
}
結果爲:
由於代碼中 synchronized (num)鎖的是num這個實例對象;
又由於 Integer num=Integer.valueOf(i),這5次創建過程中,對應的是不同的num實例對象;
所以對於代碼中的那5個線程,每次執行fun2(num)方法時,鎖的都不是同一個num的鎖,他們互不影響,所以5個線程同時執行;