前言
相信大家都聽說過線程安全問題,在學(xué)習(xí)操作系統(tǒng)的時(shí)候有一個(gè)知識(shí)點(diǎn)是臨界資源,簡(jiǎn)單的說就是一次只能讓一個(gè)進(jìn)程操作的資源,但是我們?cè)谑褂枚嗑€程的時(shí)候是并發(fā)操作的,并不能控制同時(shí)只對(duì)一個(gè)資源的訪問和修改,想要控制那么有幾種操作,今天我們就來講講第一種方法:線程同步塊或者線程同步方法(synchronized)
實(shí)例
下面舉一個(gè)例子說明
synchronized
關(guān)鍵字的使用
線程同步方法
public class Sychor { public void insert(Thread thread) { for (int i = 0; i < 10; i++) { System.out.println(thread.getName() + "輸出: " + i); } } public static void main(String[] args) { final Sychor sychor = new Sychor(); Thread t1 = new Thread() { public void run() { sychor.insert(Thread.currentThread()); }; }; Thread t2 = new Thread() { public void run() { sychor.insert(Thread.currentThread()); }; }; t1.start(); t2.start(); } }
其中輸出結(jié)果為下圖
從上面的結(jié)果可以看出這里的兩個(gè)線程是同時(shí)執(zhí)行
insert()
方法的,下面我們?cè)谠械拇a上添加synchronized
關(guān)鍵字看看效果如何,代碼如下:
public class Sychor { public synchronized void insert(Thread thread) { for (int i = 0; i < 10; i++) { System.out.println(thread.getName() + "輸出: " + i); } } public static void main(String[] args) { final Sychor sychor = new Sychor(); Thread t1 = new Thread() { public void run() { sychor.insert(Thread.currentThread()); }; }; Thread t2 = new Thread() { public void run() { sychor.insert(Thread.currentThread()); }; }; t1.start(); t2.start(); } }
上面程序的運(yùn)行結(jié)果我就不列出來,自己可以試試,總之就是加上了
synchronized
關(guān)鍵字使得線程是一個(gè)一個(gè)的執(zhí)行的,只有先執(zhí)行完一個(gè)線程才能執(zhí)行了另外一個(gè)線程。
線程同步塊
當(dāng)然上面的我們使用的是線程同步方法,我們可以使用線程同步塊,這兩個(gè)相比線程同步塊更加靈活,只需要將需要同步的代碼放在同步塊中即可,代碼如下;
public class Sychor { public void insert(Thread thread) { synchronized (this) { for (int i = 0; i < 10; i++) { System.out.println(thread.getName() + "輸出: " + i); } } } public static void main(String[] args) { final Sychor sychor = new Sychor(); Thread t1 = new Thread() { public void run() { sychor.insert(Thread.currentThread()); }; }; Thread t2 = new Thread() { public void run() { sychor.insert(Thread.currentThread()); }; }; t1.start(); t2.start(); } }
從上面的代碼中可以看出這種方式更加靈活,只需要將需要同步的代碼方法在同步塊中,不需要同步的代碼放在外面
詳細(xì)原因
我們知道每一個(gè)對(duì)象都有一把鎖,當(dāng)我們使用線程同步方法或者線程同步塊的時(shí)候?qū)嶋H上獲得是對(duì)象的唯一的一把鎖,當(dāng)一個(gè)線程獲得了這唯一的鎖,那么其他的線程只能拒之門外了,注意這里我們說是一個(gè)對(duì)象,也就是說是同一個(gè)對(duì)象,如果是不同的對(duì)象,那么就不起作用了,因?yàn)椴煌瑢?duì)象有不同的對(duì)象鎖,比如我們將上面的程序改成如下:
public class Sychor { public void insert(Thread thread) { synchronized (this) { for (int i = 0; i < 10; i++) { System.out.println(thread.getName() + "輸出: " + i); } } } public static void main(String[] args) { //第一個(gè)線程 Thread t1 = new Thread() { public void run() { Sychor sychor = new Sychor(); //在run() 方法中創(chuàng)建一個(gè)對(duì)象 sychor.insert(Thread.currentThread()); }; }; //第二個(gè)線程 Thread t2 = new Thread() { public void run() { Sychor sychor = new Sychor(); //創(chuàng)建另外的一個(gè)對(duì)象 sychor.insert(Thread.currentThread()); }; }; t1.start(); t2.start(); } }
從上面的結(jié)果可知,此時(shí)線程同步塊根本不起作用,因?yàn)樗麄冋{(diào)用的是不同對(duì)象的insert方法,獲得鎖是不一樣的
上面我們已經(jīng)說過一個(gè)對(duì)象有一把鎖,線程同步方法和線程同步塊實(shí)際獲得的是對(duì)象的鎖,因此線程同步塊的括號(hào)中填入的是
this
,我們都知道this
在一個(gè)類中的含義
一個(gè)類也有唯一的一把鎖,我們前面說的是使用對(duì)象調(diào)用成員方法,現(xiàn)在如果我們要調(diào)用類中的靜態(tài)方法,那么我們可以使用線程同步方法或者同步塊獲得類中的唯一一把鎖,那么對(duì)于多個(gè)線程同時(shí)調(diào)用同一個(gè)類中的靜態(tài)方法就可以實(shí)現(xiàn)控制了,代碼如下:
public class Sychor { // 靜態(tài)方法 public static synchronized void insert(Thread thread) { for(int i=0;i<10;i++) { System.out.println(thread.getName()+"輸出 "+i); } } public static void main(String[] args) { //第一個(gè)線程 Thread t1 = new Thread() { public void run() { Sychor.insert(Thread.currentThread()); //直接使用類調(diào)用靜態(tài)方法 }; }; //第二個(gè)線程 Thread t2 = new Thread() { public void run() { Sychor.insert(Thread.currentThread()); //直接使用類調(diào)用靜態(tài)方法 }; }; t1.start(); t2.start(); } }
注意
要想實(shí)現(xiàn)線程安全和同步控制,如果執(zhí)行的是非
static
同步方法或者其中的同步塊,那么一定要使用同一個(gè)對(duì)象,如果調(diào)用的是static同步方法或者其中的同步塊那么一定要使用同一個(gè)類去調(diào)用
如果一個(gè)線程訪問的是
static
同步方法,而另外一個(gè)線程訪問的是非static的同步方法,此時(shí)這兩個(gè)是不會(huì)發(fā)生沖突的,因?yàn)橐粋€(gè)是類的鎖,一個(gè)是對(duì)象的鎖
如果使用線程同步塊,那么同步塊中的代碼是控制訪問的,但是外面的代碼是所有線程都可以訪問的
當(dāng)一個(gè)正在執(zhí)行同步代碼塊的線程出現(xiàn)了異常,那么
jvm
會(huì)自動(dòng)釋放當(dāng)前線程所占用的鎖,因此不會(huì)出現(xiàn)由于異常導(dǎo)致死鎖的現(xiàn)象
參考文章
更多文章請(qǐng)看本人的獨(dú)立博客https://chenjiabing666.github.io/
http://www.cnblogs.com/Chenjiabing/p/7057635.html