問題:static 修飾的Synchronized 方法和非 static Synchronized 方法區別?
這個問題是一個同事在一次無意間中問過我的;在解釋之前,我們先來看兩個demo;我覺得通過代碼來講解釋最容易理解的:
demo1:
/**
*
* @author leo-zeng
*
*/
public class SynchronizedDemo {
public static synchronized void staticTest() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
System.out.println("static test"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void test() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
System.out.println(" test"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//SynchronizedDemo 類的兩個實例
final SynchronizedDemo d1 = new SynchronizedDemo();
final SynchronizedDemo d2 = new SynchronizedDemo();
//線程1
Thread thread1 = new Thread(new Runnable() {
public void run() {
d1.test();
}
}, "a");
//線程2
Thread thread2 = new Thread(new Runnable() {
public void run() {
d2.test();
}
}, "b");
thread1.start();
thread2.start();
}
}
demo1 得到的結果是:
testa
testb
testa
testb
testa
testb
testa
testb
testa
testb
發現Synchronized 對於本例中並沒有起作用;
再看看demo2:
/**
*
* @author leo-zeng
*
*/
public class StaticSynchronizedDemo {
public static synchronized void staticTest() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
System.out.println("static test"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void test() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
System.out.println(" test"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final StaticSynchronizedDemo d1 = new StaticSynchronizedDemo();
final StaticSynchronizedDemo d2 = new StaticSynchronizedDemo();
Thread thread1 = new Thread(new Runnable() {
public void run() {
StaticSynchronizedDemo.staticTest();
}
}, "b");
Thread thread2 = new Thread(new Runnable() {
public void run() {
StaticSynchronizedDemo.staticTest();
}
}, "a");
thread1.start();
thread2.start();
}
}
得到的結果:static testb
static testb
static testb
static testb
static testb
static testa
static testa
static testa
static testa
static testa
發現 兩個線程被Synchronized 加上說了;線程同步走了; 爲什麼會這樣呢;其實從兩個例子就很好的回答了上面那個問題。
synchronized是對類的當前實例進行加鎖,防止其他線程同時訪問該類的該實例的所有synchronized塊,記住看好了是該類的”當前實例“;demo1中 我們線程調用的是類的不同實例,所以synchronized對類的不同實例沒有約束。再看看demo2;static
synchronized恰好就是要控制類的所有實例的訪問了,static synchronized是限制線程同時訪問jvm中該類的所有實例同時訪問對應的代碼快。實際上,在類中某方法或某代碼塊中有 synchronized,那麼在生成一個該類實例後,改類也就有一個監視快,放置線程併發訪問改實例synchronized保護塊,而static synchronized則是所有該類的實例公用一個監視快了,也也就是兩個的區別了;可以總結說:synchronized
是 this.synchronized;而static
synchronized 是類的synchronized;
拓展:
看下demo3
public class SynchronizedDemo3 {
private final static Integer lock = new Integer(0);
/**
* 靜態方法
*/
public static void staticTest(){
//鎖住lock 對象
synchronized (lock) {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(1000);
System.out.println(" static test"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void test(){
synchronized (lock) {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(1000);
System.out.println(" test"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
final SynchronizedDemo3 s1 =new SynchronizedDemo3();
final SynchronizedDemo3 s2 =new SynchronizedDemo3();
Thread thread1 = new Thread(new Runnable() {
public void run() {
SynchronizedDemo3.staticTest();
}
}, "b");
Thread thread2 = new Thread(new Runnable() {
public void run() {
s1.test();
}
}, "a");
Thread thread3 = new Thread(new Runnable() {
public void run() {
s2.test();
}
}, "c");
thread1.start();
thread2.start();
thread3.start();
}
}
得到的結果就是
static testb
static testb
static testb
testc
testc
testc
testa
testa
testa
因爲Syssynchronized (lock) ;加在同一個object 對象上;所以就確保了類的所有對象都能約束到了。
y