synchronized 加到 static 方法前面是給class 加鎖,即類鎖;而synchronized 加到非靜態方法前面是給對象上鎖。這兩者的區別我用代碼來演示下:
1.類鎖和對象鎖是兩把不同的鎖,多線程執行兩個不同鎖的方法時是異步的
加鎖的類(下面幾個此類不變)
public class Task2 {
public synchronized static void doLongTimeTaskA() {
System.out.println("name = " + Thread.currentThread().getName() + ", begain");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end");
}
public synchronized static void doLongTimeTaskB() {
System.out.println("name = " + Thread.currentThread().getName() + ", begain");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end");
}
public synchronized void doLongTimeTaskC() {
System.out.println("name = " + Thread.currentThread().getName() + ", begain");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end");
}
}
多線程如下
class ThreadA extends Thread {
private Task2 mTask2;
public ThreadA(Task2 tk) {
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskA();
}
}
class ThreadB extends Thread {
private Task2 mTask2;
public ThreadB(Task2 tk) {
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskB();
}
}
class ThreadC extends Thread {
private Task2 mTask2;
public ThreadC(Task2 tk) {
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskC();
}
}
main函數如下
public static void main(String[] args) {
Task2 mTask2 = new Task2();
ThreadA ta = new ThreadA(mTask2);
ThreadB tb = new ThreadB(mTask2);
ThreadC tc = new ThreadC(mTask2);
ta.setName("A");
tb.setName("B");
tc.setName("C");
ta.start();
tb.start();
tc.start();
}
執行結果如下
name = A, begain
name = C, begain
name = C, end
name = A, end
name = B, begain
name = B, end
doLongTimeTaskA()和 doLongTimeTaskB()互斥,與doLongTimeTaskC()不互斥,類鎖和對象鎖是兩類不同的鎖
2,對象鎖對同一個實列對象起作用,類鎖對該類的所有實列對象起作用
加鎖類不變,用上面的
多線程更改如下
class ThreadA extends Thread{
private Task2 mTask2;
public ThreadA(Task2 tk){
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskC();
}
}
class ThreadB extends Thread{
private Task2 mTask2;
public ThreadB(Task2 tk){
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskC();
}
}
main函數如下
public static void main(String[] args) {
Task2 mTaska = new Task2();
Task2 mTaskb = new Task2();
ThreadA ta = new ThreadA(mTaska );
ThreadB tb = new ThreadB(mTaskb );
ta.setName("A");
tb.setName("B");
ta.start();
tb.start();
}
運行結果如下
name = A, begain
name = B, begain
name = A, end
name = B, end
對象鎖鎖的對象不一樣,分別是mTaska , mTaskb,所以線程A和線程B調用 doLongTimeTaskC 是異步執行的。
然後我們main函數不變,依舊是對兩個實列而言 ,更改多線程的class走類鎖,執行doLongTimeTaskA()或者doLongTimeTaskB()
更改後的多線程類如下
class ThreadA extends Thread{
private Task2 mTask2;
public ThreadA(Task2 tk){
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskA();
}
}
class ThreadB extends Thread{
private Task2 mTask2;
public ThreadB(Task2 tk){
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskB();
}
}
結果如下
name = A, begain
name = A, end
name = B, begain
name = B, end
可以看出 在線程A執行完doLongTimeTaskA方法後,線程B纔會獲得該類鎖接着去執行doLongTimeTaskA。也就是說,類鎖對所有的該類對象都能起作用。
結論:
1. 如果多線程同時訪問同一類的 類鎖(synchronized 修飾的靜態方法)以及對象鎖(synchronized 修飾的非靜態方法)這兩個方法執行是異步的,原因:類鎖和對象鎖是2種不同的鎖。
2. 類鎖對該類的所有對象都能起作用,而對象鎖只對同一個實例對象起作用。