synchronized的用法及驗證
阿新 • • 發佈:2018-11-09
synchronized有四種用法:
1、修飾普通方法與靜態方法,放在範圍操作符(public等)之後,返回型別宣告(void等)之前。
2、對某一程式碼塊使用,synchronized後跟括號,括號裡是變數、物件、類。
修飾普通方法與靜態方法,那麼他們的鎖分別是什麼呢?讓我們一起驗證一下。
不加鎖
public class SynWork { private int index; public void synMethod1(int index) { for (int i = 0; i < 3; i++) { try { this.index = index; System.out.println("synMethod1:" + Thread.currentThread().getName() + ":" + this.index); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } public void synMethod2(int index) { for (int i = 0; i < 3; i++) { try { this.index = index; System.out.println("synMethod2:" + Thread.currentThread().getName() + ":" + this.index); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }
public class SynTest { public static void main(String[] args) { SynWork synWork = new SynWork(); Thread thread1 = new Thread(new Runnable() { @Override public void run() { synWork.synMethod1(1); } }, "T1"); Thread thread2 = new Thread(new Runnable() { @Override public void run() { synWork.synMethod1(2); } }, "T2"); Thread thread3 = new Thread(new Runnable() { @Override public void run() { synWork.synMethod2(30); } }, "T3"); Thread thread4 = new Thread(new Runnable() { @Override public void run() { synWork.synMethod2(40); } }, "T4"); thread1.start(); thread2.start(); thread3.start(); thread4.start(); } }
執行結果:
synMethod1:T2:2
synMethod2:T4:40
synMethod2:T3:30
synMethod1:T1:2
synMethod2:T3:30
synMethod1:T1:1
synMethod2:T4:40
synMethod1:T2:2
synMethod1:T2:30
synMethod1:T1:30
synMethod2:T3:30
synMethod2:T4:30
枷鎖後
public class SynWork { private int index; public synchronized void synMethod1(int index) { for (int i = 0; i < 3; i++) { try { this.index = index; System.out.println("synMethod1:" + Thread.currentThread().getName() + ":" + this.index); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } public synchronized void synMethod2(int index) { for (int i = 0; i < 3; i++) { try { this.index = index; System.out.println("synMethod2:" + Thread.currentThread().getName() + ":" + this.index); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }
執行結果:
synMethod1:T1:1
synMethod1:T1:1
synMethod1:T1:1
synMethod2:T4:40
synMethod2:T4:40
synMethod2:T4:40
synMethod1:T2:2
synMethod1:T2:2
synMethod1:T2:2
synMethod2:T3:30
synMethod2:T3:30
synMethod2:T3:30
繼續驗證
public class SynWork {
private static int _index;
public synchronized void synMethod1(int index) {
for (int i = 0; i < 3; i++) {
try {
_index = index;
System.out.println("synMethod1:" + Thread.currentThread().getName() + ":" + _index);
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void synMethod2(int index) {
for (int i = 0; i < 3; i++) {
try {
_index = index;
System.out.println("synMethod2:" + Thread.currentThread().getName() + ":" + _index);
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class SynTest {
public static void main(String[] args) {
SynWork synWork = new SynWork();
SynWork synWork2 = new SynWork();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synWork.synMethod1(1);
}
}, "T1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
synWork2.synMethod1(2);
}
}, "T2");
Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
synWork.synMethod2(30);
}
}, "T3");
Thread thread4 = new Thread(new Runnable() {
@Override
public void run() {
synWork2.synMethod2(40);
}
}, "T4");
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
執行結果:
synMethod1:T1:2
synMethod1:T2:2
synMethod1:T2:2
synMethod1:T1:1
synMethod1:T2:2
synMethod1:T1:2
synMethod2:T3:30
synMethod2:T4:30
synMethod2:T3:30
synMethod2:T4:40
synMethod2:T3:30
synMethod2:T4:40
由此可知修飾普通方法的鎖是方法所在類的物件。
在一個類裡,同時修飾普通方法和靜態方法
public class SynWork {
private static int _index;
// 普通方法
public synchronized void synMethod1(int index) {
for (int i = 0; i < 3; i++) {
try {
_index = index;
System.out.println("synMethod1:" + Thread.currentThread().getName() + ":" + _index);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 靜態方法
public synchronized static void synMethod2(int index) {
for (int i = 0; i < 3; i++) {
try {
_index = index;
System.out.println("synMethod2:" + Thread.currentThread().getName() + ":" + _index);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class SynTest {
public static void main(String[] args) {
SynWork synWork = new SynWork();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synWork.synMethod1(1);
}
}, "T1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
synWork.synMethod1(2);
}
}, "T2");
Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
SynWork.synMethod2(30);
}
}, "T3");
Thread thread4 = new Thread(new Runnable() {
@Override
public void run() {
SynWork.synMethod2(40);
}
}, "T4");
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
執行結果:
synMethod1:T1:1
synMethod2:T3:30
synMethod2:T3:30
synMethod1:T1:30
synMethod2:T3:30
synMethod1:T1:30
synMethod1:T2:2
synMethod2:T4:40
synMethod1:T2:2
synMethod2:T4:40
synMethod2:T4:2
synMethod1:T2:2
繼續驗證
public class SynWork {
private static int _index;
// 普通方法
public void synMethod1(int index) {
synchronized (SynWork.class) {
for (int i = 0; i < 3; i++) {
try {
_index = index;
System.out.println("synMethod1:" + Thread.currentThread().getName() + ":" + _index);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 靜態方法
public synchronized static void synMethod2(int index) {
for (int i = 0; i < 3; i++) {
try {
_index = index;
System.out.println("synMethod2:" + Thread.currentThread().getName() + ":" + _index);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class SynTest {
public static void main(String[] args) {
SynWork synWork = new SynWork();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synWork.synMethod1(1);
}
}, "T1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
synWork.synMethod1(2);
}
}, "T2");
Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
SynWork.synMethod2(30);
}
}, "T3");
Thread thread4 = new Thread(new Runnable() {
@Override
public void run() {
SynWork.synMethod2(40);
}
}, "T4");
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
執行結果:
synMethod1:T1:1
synMethod1:T1:1
synMethod1:T1:1
synMethod2:T4:40
synMethod2:T4:40
synMethod2:T4:40
synMethod1:T2:2
synMethod1:T2:2
synMethod1:T2:2
synMethod2:T3:30
synMethod2:T3:30
synMethod2:T3:30
由此可知,修飾靜態方法和普通方法不是同一個鎖,靜態方法的鎖是方法所在的類,即SynWork.class
synchronized修飾程式碼塊
public class SynWork {
public static int _index;
// 普通方法
public void synMethod1(int index) {
synchronized (SynWork.class) {
for (int i = 0; i < 3; i++) {
try {
_index = index;
System.out.println("synMethod1:" + Thread.currentThread().getName() + ":" + _index);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 靜態方法
public synchronized static void synMethod2(int index) {
for (int i = 0; i < 3; i++) {
try {
_index = index;
System.out.println("synMethod2:" + Thread.currentThread().getName() + ":" + _index);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Syn2Work {
// 普通方法
public void synMethod1(int index) {
synchronized (SynWork.class) {
for (int i = 0; i < 3; i++) {
try {
SynWork._index = index;
System.out.println("synMethod1:" + Thread.currentThread().getName() + ":" + SynWork._index);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class SynTest {
public static void main(String[] args) {
SynWork synWork = new SynWork();
Syn2Work syn2Work = new Syn2Work();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synWork.synMethod1(1);
}
}, "T1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
syn2Work.synMethod1(2);
}
}, "T2");
Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
SynWork.synMethod2(30);
}
}, "T3");
thread1.start();
thread2.start();
thread3.start();
}
}
執行結果:
synMethod1:T1:1
synMethod1:T1:1
synMethod1:T1:1
synMethod2:T3:30
synMethod2:T3:30
synMethod2:T3:30
synMethod1:T2:2
synMethod1:T2:2
synMethod1:T2:2
結論:
1、synchronized修飾普通方法時,鎖的是方法所在類的物件,等同於synchronized(this){}。
2、synchronized修飾static方法時,鎖的是方法所在類的class,等同於synchronized(類的clas){}。
3、synchronized修飾程式碼塊時,鎖是括號裡的引數,括號中的引數一致時(==),則會形成互斥。
4、在使用synchronized時,用程式碼塊更靈活,儘量縮小其影響範圍