歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Java中利用synchronized關鍵字實現多線程同步問題

Java中利用synchronized關鍵字實現多線程同步問題

日期:2017/3/1 9:39:50   编辑:Linux編程

Java 中多線程的同步依靠的是對象鎖機制,synchronized關鍵字就是利用了封裝對象鎖來實現對共享資源的互斥訪問。

下面以一個簡單例子來說明多線程同步問題,我們希望在run()方法裡加入synchronized關鍵字來實現互斥訪問。

package com.clark.thread;

public class MyThread implements Runnable{
private int threadId;

public MyThread(int id){
this.threadId = id;
}
@Override
public synchronized void run() {
//此時關鍵字synchronized鎖住的是this對象,即當前運行線程對象本身
for (int i = 0; i < 100; i++) {
if(i % 10 ==0){
System.out.println();
}
System.out.print("Thread ID:"+this.threadId+":"+i+" ");
}
}

}

測試類:

package com.clark.thread;

public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
//代碼中創建了10個線程,而每個線程都持有this對象的對象鎖,這不能實現線程的同步。
for (int i = 0; i < 10; i++) {
new Thread(new MyThread(i)).start();
Thread.sleep(1);
}
}
}

打印結果部分如下:其線程不是互斥訪問的。因此沒有達到資源多線程同步效果。。。

Thread ID:1:60 Thread ID:1:61 Thread ID:1:62 Thread ID:1:63 Thread ID:1:64 Thread ID:1:65 Thread ID:1:66 Thread ID:1:67 Thread ID:1:68 Thread ID:1:69
Thread ID:1:70 Thread ID:1:71 Thread ID:1:72 Thread ID:1:73 Thread ID:1:74 Thread ID:1:75 Thread ID:1:76
Thread ID:1:77 Thread ID:1:78 Thread ID:1:79
Thread ID:1:80 Thread ID:1:81 Thread ID:2:0 Thread ID:1:82 Thread ID:1:83 Thread ID:1:84 Thread ID:1:85 Thread ID:1:86 Thread ID:1:87 Thread ID:1:88 Thread ID:1:89
Thread ID:1:90 Thread ID:1:91 Thread ID:1:92 Thread ID:1:93 Thread ID:1:94 Thread ID:1:95 Thread ID:2:1 Thread ID:2:2 Thread ID:2:3 Thread ID:2:4 Thread ID:2:5 Thread ID:2:6 Thread ID:2:7 Thread ID:2:8 Thread ID:2:9

從上述得知,要想實現線程同步,必須讓這些線程去競爭一個唯一的共享對象鎖。

package com.clark.thread;

public class MyThread implements Runnable{
private int threadId;
private Object object;//線程之間競爭使用的對象鎖
public MyThread(int id,Object object){
this.threadId = id;
this.object = object;
}
@Override
public void run() {
/**
* 將這個object對象的引用傳遞給每一個線程對象的lock成員變量
* 從而每個線程的lock成員都指向同一個Object對象
* 這樣就可以讓線程去競爭這個唯一的共享的對象鎖,從而實現同步。
*/
synchronized(object){
for (int i = 0; i < 100; i++) {
if(i % 10 ==0){
System.out.println();
}
System.out.print("Thread ID:"+this.threadId+":"+i+" ");
}
}
}

}

package com.clark.thread;

public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
Object obj = new Object();
for (int i = 0; i < 10; i++) {
new Thread(new MyThread(i,obj)).start();
Thread.sleep(1);
}
}
}

測試結果如下:

Thread ID:5:60 Thread ID:5:61 Thread ID:5:62 Thread ID:5:63 Thread ID:5:64 Thread ID:5:65 Thread ID:5:66 Thread ID:5:67 Thread ID:5:68 Thread ID:5:69
Thread ID:5:70 Thread ID:5:71 Thread ID:5:72 Thread ID:5:73 Thread ID:5:74 Thread ID:5:75 Thread ID:5:76 Thread ID:5:77 Thread ID:5:78 Thread ID:5:79
Thread ID:5:80 Thread ID:5:81 Thread ID:5:82 Thread ID:5:83 Thread ID:5:84 Thread ID:5:85 Thread ID:5:86 Thread ID:5:87 Thread ID:5:88 Thread ID:5:89
Thread ID:5:90 Thread ID:5:91 Thread ID:5:92 Thread ID:5:93 Thread ID:5:94 Thread ID:5:95 Thread ID:5:96 Thread ID:5:97 Thread ID:5:98 Thread ID:5:99
Thread ID:6:0 Thread ID:6:1 Thread ID:6:2 Thread ID:6:3 Thread ID:6:4 Thread ID:6:5 Thread ID:6:6 Thread ID:6:7 Thread ID:6:8 Thread ID:6:9
Thread ID:6:10 Thread ID:6:11 Thread ID:6:12 Thread ID:6:13 Thread ID:6:14 Thread ID:6:15 Thread ID:6:16 Thread ID:6:17 Thread ID:6:18 Thread ID:6:19
Thread ID:6:20 Thread ID:6:21 Thread ID:6:22 Thread ID:6:23 Thread ID:6:24 Thread ID:6:25 Thread ID:6:26 Thread ID:6:27 Thread ID:6:28 Thread ID:6:29

從第二段代碼可知,同步的關鍵是多個線程對象競爭同一個共享資源即可,上面的代碼中是通過外部創建共享資源,然後傳遞到線程中來實現。我們也可以利用類成員變量被所有類的實例所共享這一特性,因此可以將lock用靜態成員對象來實現,代碼如下所示:修改MyThread.java類如下

package com.clark.thread;

public class MyThread implements Runnable{
private int threadId;
private static Object object = new Object();//線程之間競爭使用的對象鎖
public MyThread(int id){
this.threadId = id;
}
@Override
public void run() {
<strong>/**
* 將這個object對象的引用傳遞給每一個線程對象的lock成員變量
* 從而每個線程的lock成員都指向同一個Object對象
* 這樣就可以讓線程去競爭這個唯一的共享的對象鎖,從而實現同步。
*/</strong>
synchronized(object){
for (int i = 0; i < 100; i++) {
if(i % 10 ==0){
System.out.println();
}
System.out.print("Thread ID:"+this.threadId+":"+i+" ");
}
}
}

}

結果如下:

Thread ID:0:0 Thread ID:0:1 Thread ID:0:2 Thread ID:0:3 Thread ID:0:4 Thread ID:0:5 Thread ID:0:6 Thread ID:0:7 Thread ID:0:8 Thread ID:0:9
Thread ID:0:10 Thread ID:0:11 Thread ID:0:12 Thread ID:0:13 Thread ID:0:14 Thread ID:0:15 Thread ID:0:16 Thread ID:0:17 Thread ID:0:18 Thread ID:0:19
Thread ID:0:20 Thread ID:0:21 Thread ID:0:22 Thread ID:0:23 Thread ID:0:24 Thread ID:0:25 Thread ID:0:26 Thread ID:0:27 Thread ID:0:28 Thread ID:0:29
Thread ID:0:30 Thread ID:0:31 Thread ID:0:32 Thread ID:0:33 Thread ID:0:34 Thread ID:0:35 Thread ID:0:36 Thread ID:0:37 Thread ID:0:38 Thread ID:0:39

再來看第一段代碼,實例方法中加入sychronized關鍵字封鎖的是this對象本身,而在靜態方法中加入sychronized關鍵字封鎖的就是類本身。靜態方法是所有類實例對象所共享的,因此線程對象在訪問此靜態方法時是互斥訪問的,從而可以實現線程的同步,代碼如下所示:

package com.clark.thread;

public class MyThread implements Runnable{
private int threadId;
public MyThread(int id){
this.threadId = id;
}
@Override
public void run() {
start(this.threadId);
}
private static synchronized void start(int threadId2) {
for (int i = 0; i < 100; i++) {
if(i % 10 == 0){
System.out.println();
}
System.out.print("Thread ID:"+threadId2+":"+i+" ");
}
}

}

結果如下=========

Thread ID:0:0 Thread ID:0:1 Thread ID:0:2 Thread ID:0:3 Thread ID:0:4 Thread ID:0:5 Thread ID:0:6 Thread ID:0:7 Thread ID:0:8 Thread ID:0:9 Thread ID:0:10 Thread ID:0:11 Thread ID:0:12 Thread ID:0:13 Thread ID:0:14 Thread ID:0:15 Thread ID:0:16 Thread ID:0:17 Thread ID:0:18 Thread ID:0:19 Thread ID:0:20 Thread ID:0:21 Thread ID:0:22 Thread ID:0:23 Thread ID:0:24 Thread ID:0:25 Thread ID:0:26 Thread ID:0:27 Thread ID:0:28 Thread ID:0:29 Thread ID:0:30 Thread ID:0:31 Thread ID:0:32 Thread ID:0:33 Thread ID:0:34 Thread ID:0:35 Thread ID:0:36 Thread ID:0:37 Thread ID:0:38 Thread ID:0:39 Thread ID:0:40 Thread ID:0:41 Thread ID:0:42 Thread ID:0:43 Thread ID:0:44 Thread ID:0:45 Thread ID:0:46 Thread ID:0:47 Thread ID:0:48 Thread ID:0:49 Thread ID:0:50 Thread ID:0:51 Thread ID:0:52 Thread ID:0:53 Thread ID:0:54 Thread ID:0:55 Thread ID:0:56 Thread ID:0:57 Thread ID:0:58 Thread ID:0:59

Java1.5後的多線程框架 http://www.linuxidc.com/Linux/2014-02/96879.htm

Java多線程和同步的理解 http://www.linuxidc.com/Linux/2013-12/93691.htm

Java中兩種實現多線程方式的對比分析 http://www.linuxidc.com/Linux/2013-12/93690.htm

Java利用多線程計算目錄數據大小 http://www.linuxidc.com/Linux/2013-09/90715.htm

Java多線程向數據庫寫入數據 http://www.linuxidc.com/Linux/2013-09/90297.htm

Java多線程經典案例 http://www.linuxidc.com/Linux/2014-06/103458.htm

Copyright © Linux教程網 All Rights Reserved