java中synchronized 用在例項方法和物件方法上面的區別
https://bijian1013.iteye.com/blog/1836575
在Java中,synchronized 是用來表示同步的,我們可以synchronized 來修飾一個方法。也可以synchronized 來修飾方法裡面的一個語句塊。
修飾例項方法:
Java程式碼- public synchronized void normalMethod() throws InterruptedException {
- for (int i = 0; i < 10; i++) {
- Thread.sleep(1000);
- System.out.println("normalMethod:" + i);
- }
- }
修飾類方法(static 方法):
Java程式碼- public static synchronized void staticMethod() throws InterruptedException {
- for (int i = 0; i < 10; i++) {
- Thread.sleep(500);
- System.out.println("staticMethod:" + i);
- }
- }
修飾方法裡面語句塊:
Java程式碼- 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:
Java程式碼- 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();
- }
- }
執行結果:
Text程式碼- 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如下:
Java程式碼- 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();
- }
- }
執行結果:
Text程式碼- 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例項,如再建立一個例項,則就有問題了。如下所示:
Java程式碼
- 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();
- }
- }
執行結果:
Text程式碼- 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:
Java程式碼- 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();
- }
- }
執行結果:
Text程式碼- 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