https://bijian1013.iteye.com/blog/1836575
在Java中,synchronized 是用來表示同步的,我們可以synchronized 來修飾一個方法。也可以synchronized 來修飾方法里面的一個語句塊。
修飾實例方法:
- public synchronized void normalMethod() throws InterruptedException {
- for (int i = 0; i < 10; i++) {
- Thread.sleep(1000);
- System.out.println("normalMethod:" + i);
- }
- }
修飾類方法(static 方法):
- public static synchronized void staticMethod() throws InterruptedException {
- for (int i = 0; i < 10; i++) {
- Thread.sleep(500);
- System.out.println("staticMethod:" + i);
- }
- }
修飾方法里面語句塊:
- public static void staticMethod() throws InterruptedException {
- synchronized (locks) {
- for (int i = 0; i < 10; i++) {
- Thread.sleep(1000);
- System.out.println("staticMethod:" + i);
- }
- }
- }
注意:這里不能用synchronized修飾方法外面的語句塊(我把他叫做類語句塊),雖然我們可以在方法外面定義語句塊,這樣做會遇到編譯錯誤,這里涉及到了Java里面的對象初始化的部分知識。大概的原因就是synchronized鎖住的是對象,當初始化對象的時候,JVM在對象初始化完成之前會調用方法外面的語句塊,這個時候對象還不存在,所以就不存在鎖了。
那么,在static方法和非static方法前面加synchronized到底有什么不同呢?
static的方法屬於類方法,它屬於這個Class(注意:這里的Class不是指Class的某個具體對象),那么static獲取到的鎖,就是當前調用這個方法的對象所屬的類(Class,而不再是由這個Class產生的某個具體對象了)。而非static方法獲取到的鎖,就是當前調用這個方法的對象的鎖了。所以,他們之間不會產生互斥。
實例1:
- package com.bijian.thread;
- public class SynchronizedTest {
- public static synchronized void staticMethod() throws InterruptedException {
- for (int i = 0; i < 10; i++) {
- Thread.sleep(500);
- System.out.println("staticMethod:" + i);
- }
- }
- public synchronized void normalMethod() throws InterruptedException {
- for (int i = 0; i < 10; i++) {
- Thread.sleep(1000);
- System.out.println("normalMethod:" + i);
- }
- }
- public static void main(String[] args) {
- final SynchronizedTest synchronizedTest = new SynchronizedTest();
- Thread thread = new Thread(new Runnable() {
- public void run() {
- try {
- synchronizedTest.normalMethod();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }, "a");
- Thread thread1 = new Thread(new Runnable() {
- public void run() {
- try {
- SynchronizedTest.staticMethod();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }, "b");
- thread1.start();
- thread.start();
- }
- }
運行結果:
- staticMethod:0
- normalMethod:0
- staticMethod:1
- staticMethod:2
- normalMethod:1
- staticMethod:3
- staticMethod:4
- normalMethod:2
- staticMethod:5
- staticMethod:6
- normalMethod:3
- staticMethod:7
- staticMethod:8
- normalMethod:4
- staticMethod:9
- normalMethod:5
- normalMethod:6
- normalMethod:7
- normalMethod:8
- normalMethod:9
那當我們想讓所有這個類下面的對象都同步的時候,也就是讓所有這個類下面的對象共用同一把鎖的時候,我們如何辦呢?
法1:將normalMethod方法也改成static,這樣這兩個static方法都屬於類方法,它們獲取到的鎖都是當前調用這個方法的對象所屬的類(Class,而不再是由這個Class產生的某個具體對象了)。但這樣會影響代碼結構和對象的封裝性。
修改實例1如下:
- package com.bijian.thread;
- public class SynchronizedTest {
- public static synchronized void staticMethod() throws InterruptedException {
- for (int i = 0; i < 10; i++) {
- Thread.sleep(500);
- System.out.println("staticMethod:" + i);
- }
- }
- public static synchronized void normalMethod() throws InterruptedException {
- for (int i = 0; i < 10; i++) {
- Thread.sleep(1000);
- System.out.println("normalMethod:" + i);
- }
- }
- public static void main(String[] args) {
- Thread thread = new Thread(new Runnable() {
- public void run() {
- try {
- SynchronizedTest.normalMethod();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }, "a");
- Thread thread1 = new Thread(new Runnable() {
- public void run() {
- try {
- SynchronizedTest.staticMethod();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }, "b");
- thread1.start();
- thread.start();
- }
- }
運行結果:
- staticMethod:0
- staticMethod:1
- staticMethod:2
- staticMethod:3
- staticMethod:4
- staticMethod:5
- staticMethod:6
- staticMethod:7
- staticMethod:8
- staticMethod:9
- normalMethod:0
- normalMethod:1
- normalMethod:2
- normalMethod:3
- normalMethod:4
- normalMethod:5
- normalMethod:6
- normalMethod:7
- normalMethod:8
- normalMethod:9
也許有人說:將實例1的staticMethod方法改成的static去掉也能達到目的。確實可以,因為非static方法獲取到的鎖,就是當前調用這個方法的對象的鎖,而實例1只有一個SynchronizedTest實例,如再創建一個實例,則就有問題了。如下所示:
- package com.bijian.thread;
- public class SynchronizedTest {
- public synchronized void staticMethod() throws InterruptedException {
- for (int i = 0; i < 10; i++) {
- Thread.sleep(500);
- System.out.println("staticMethod:" + i);
- }
- }
- public synchronized void normalMethod() throws InterruptedException {
- for (int i = 0; i < 10; i++) {
- Thread.sleep(1000);
- System.out.println("normalMethod:" + i);
- }
- }
- public static void main(String[] args) {
- final SynchronizedTest synchronizedTest = new SynchronizedTest();
- Thread thread = new Thread(new Runnable() {
- public void run() {
- try {
- synchronizedTest.normalMethod();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }, "a");
- //為了驗證獲取到的鎖都是當前調用這個方法的對象所屬的類,特另新建一個對象
- final SynchronizedTest synchronizedTest2 = new SynchronizedTest();
- Thread thread1 = new Thread(new Runnable() {
- public void run() {
- try {
- synchronizedTest2.staticMethod();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }, "b");
- thread1.start();
- thread.start();
- }
- }
運行結果:
- staticMethod:0
- staticMethod:1
- normalMethod:0
- staticMethod:2
- staticMethod:3
- normalMethod:1
- staticMethod:4
- staticMethod:5
- normalMethod:2
- staticMethod:6
- normalMethod:3
- staticMethod:7
- staticMethod:8
- normalMethod:4
- staticMethod:9
- normalMethod:5
- normalMethod:6
- normalMethod:7
- normalMethod:8
- normalMethod:9
法2:語句塊鎖,直接看如下實例:
實例2:
- package com.bijian.thread;
- public class SynchronizedTest {
- public final static Byte[] locks = new Byte[0];
- public static void staticMethod() throws InterruptedException {
- synchronized(locks) {
- for (int i = 0; i < 10; i++) {
- Thread.sleep(500);
- System.out.println("staticMethod:" + i);
- }
- }
- }
- public void normalMethod() throws InterruptedException {
- synchronized(locks) {
- for (int i = 0; i < 10; i++) {
- Thread.sleep(1000);
- System.out.println("normalMethod:" + i);
- }
- }
- }
- public static void main(String[] args) {
- final SynchronizedTest synchronizedTest = new SynchronizedTest();
- Thread thread = new Thread(new Runnable() {
- public void run() {
- try {
- synchronizedTest.normalMethod();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }, "a");
- Thread thread1 = new Thread(new Runnable() {
- public void run() {
- try {
- SynchronizedTest.staticMethod();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }, "b");
- thread1.start();
- thread.start();
- }
- }
運行結果:
- staticMethod:0
- staticMethod:1
- staticMethod:2
- staticMethod:3
- staticMethod:4
- staticMethod:5
- staticMethod:6
- staticMethod:7
- staticMethod:8
- staticMethod:9
- normalMethod:0
- normalMethod:1
- normalMethod:2
- normalMethod:3
- normalMethod:4
- normalMethod:5
- normalMethod:6
- normalMethod:7
- normalMethod:8
- normalMethod:9