這個也是我在面試中被問到的一個題目(synchronize修飾靜態方法和非靜態方法的區別),這個沒答出來
關鍵字synchronized還可以應用在static靜態方法上,如果這樣寫,那是對當前的*.java文件對應的Class類進行持鎖,測試項目:類文件Service.java代碼如下:
public class Service {
synchronized public static void PrintA(){
try {
System.out.println("線程的名稱爲:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"進入printA");
Thread.sleep(3000);
System.out.println("線程的名稱爲:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"離開printA");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
synchronized public static void PrintB(){
System.out.println("線程的名稱爲:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"進入printB");
System.out.println("線程的名稱爲:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"離開printB");
}
}
ThreadA的代碼:
public class ThreadA extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
Service.PrintA();
}
}
ThreadB:
public class ThreadB extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
Service.PrintB();
}
}
運行測試代碼:
public class Test1 {
public static void main(String[] args) throws InterruptedException {
ThreadA a = new ThreadA();
a.setName("A");
a.start();
ThreadB b = new ThreadB();
b.setName("B");
b.start();
}
}
運行結果:
從運行結果來看,並沒有什麼特別地方,都是同步的效果,和將synchronized關鍵字加到非靜態static方法上使用的效果是一樣的,其實還是有本質上的不同,synchronized關鍵字加到static靜態方法上是給Class類上鎖,而synchronized關鍵字加到非static靜態方法上是給對象上鎖:
爲了驗證不是同一個鎖。創建新的 項目,Service.java的代碼如下:
public class Service {
synchronized public static void PrintA() {
try {
System.out.println("線程的名稱爲:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "進入printA");
Thread.sleep(3000);
System.out.println("線程的名稱爲:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "離開printA");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
synchronized public static void PrintB() {
System.out.println("線程的名稱爲:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "進入printB");
System.out.println("線程的名稱爲:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "離開printB");
}
synchronized public void PrintC() {
System.out.println("線程的名稱爲:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "進入printB");
System.out.println("線程的名稱爲:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "離開printB");
}
}
ThreadA :
public class ThreadA extends Thread{
private Service service;
public ThreadA(Service service) {
// TODO Auto-generated constructor stub
super();
this.service = service;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
service.PrintA();
}
}
ThreadB:
public class ThreadB extends Thread{
private Service service;
public ThreadB(Service service) {
// TODO Auto-generated constructor stub
super();
this.service = service;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
service.PrintB();
}
}
ThreadC:
public class ThreadC extends Thread{
private Service service;
public ThreadC(Service service) {
// TODO Auto-generated constructor stub
super();
this.service = service;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
service.PrintC();
}
}
測試代碼類:
public class Test1 {
public static void main(String[] args) throws InterruptedException {
Service service = new Service();
ThreadA a = new ThreadA(service);
a.setName("A");
a.start();
ThreadB b = new ThreadB(service);
b.setName("B");
b.start();
ThreadC c = new ThreadC(service);
c.setName("C");
c.start();
}
}
運行結果:
結果產生異步的原因是持有不同的鎖,一個是對象鎖,一個是Class鎖,而Class鎖可以對類的所有對象實例起作用。如果不是Class鎖的話,則多個實例就有多個鎖,上文章有說到。下面驗證Class鎖對所有的實例起作用
修改運行測試文件如下:
public class Test1 {
public static void main(String[] args) throws InterruptedException {
Service service = new Service();
Service service2 = new Service();
ThreadA a = new ThreadA(service);
a.setName("A");
a.start();
ThreadB b = new ThreadB(service2);
b.setName("B");
b.start();
}
}
運行結果:
由結果來看,依然是同步進行的,也就是說明了Class鎖對所有實例起作用。
同步Synchronized(class) 的實質其實和synchronized static 方法一樣,都是給Class加鎖。驗證:
修改Service代碼:
public class Service {
public void PrintA() {
synchronized (Service.class) {
try {
System.out.println("線程的名稱爲:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "進入printA");
Thread.sleep(3000);
System.out.println("線程的名稱爲:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "離開printA");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void PrintB() {
synchronized (Service.class) {
System.out.println("線程的名稱爲:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "進入printB");
System.out.println("線程的名稱爲:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "離開printB");
}
}
}
注意:PrintA和PrintB方法加不加static都一樣了這時
再次運行代碼得:
結論:靜態同步synchronized方法與synchronized(class)代碼塊效果一樣,沒有本質上的區別,與非靜態的方法比起來,非靜態的是給對象上鎖。多個對象的時候會給多個對象上鎖。依舊是異步的。而靜態的方法,則因爲持有的是Class鎖,所以多個對象創建的時候,因爲其Class依舊是一樣的,所有就會是同步狀態