JAVA執行緒中的安全知識

zzc2227372發表於2014-07-16

在JAVA中,執行緒與執行緒之間的資料是共享的,因此,當多個執行緒同時改變相同的物件,執行緒會相互傾軋。根據執行緒訪問資料的不同線性,會產生被腐蝕的物件。

為了避免這種現象,我們需要對需要保護的物件上鎖,這樣在同一時間只能有一個執行緒訪問這個資料,而其他的執行緒進入等待佇列,知道這個執行緒訪問完資料並釋放鎖,等待佇列中的執行緒才能獲得鎖。

上鎖的方法有多種,這裡只寫出常用的三種

1.synchronized程式碼塊

synchronized (object)

{
}

例如:

 

public class TraditionalThreadSynchronized {
	public static void main(String[] args) {
		final Outputter output = new Outputter();
		new Thread() {
			public void run() {
				output.output("zhangsan");
			};
		}.start();		
		new Thread() {
			public void run() {
				output.output("lisi");
			};
		}.start();
	}
}
class Outputter {
	public void output(String name) {
		// TODO 為了保證對name的輸出不是一個原子操作,這裡逐個輸出name的每個字元
synchronized (this)
{
		for(int i = 0; i < name.length(); i++) {
			System.out.print(name.charAt(i));
			// Thread.sleep(10);
		}
}

	}
}

 

 

object 必須是需要互斥的多個執行緒間的共享物件。

因此下面這段程式碼的鎖是無效的

 

public class TraditionalThreadSynchronized {
	public static void main(String[] args) {
		final Outputter output = new Outputter();
		new Thread() {
			public void run() {
				output.output("zhangsan");
			};
		}.start();		
		new Thread() {
			public void run() {
				output.output("lisi");
			};
		}.start();
	}
}
class Outputter {
	public void output(String name) {
		// TODO 為了保證對name的輸出不是一個原子操作,這裡逐個輸出name的每個字元
	Object object=new Object();
synchronizedobject{
for(int i = 0; i < name.length(); i++) {
			System.out.print(name.charAt(i));
			// Thread.sleep(10);
		}
}

		
	}
}

 

 

 

 

2.synchronized 方法

public synchronized void output(String name) {
    // TODO 執行緒輸出方法
    for(int i = 0; i < name.length(); i++) {
        System.out.print(name.charAt(i));
    }
}

 這種方式就相當於用this鎖住整個方法內的程式碼塊,如果用synchronized加在靜態方法上,就相當於用××××.class鎖住整個方法內的程式碼塊。使用synchronized在某些情況下會造成死鎖,死鎖問題以後會說明。使用synchronized修飾的方法或者程式碼塊可以看成是一個原子操作

每個鎖對都有兩個佇列,一個是就緒佇列,一個是阻塞佇列,就緒佇列儲存了將要獲得鎖的執行緒,阻塞佇列儲存了被阻塞的線 程,當一個執行緒被喚醒(notify)後,才會進入到就緒佇列,等待CPU的排程,反之,當一個執行緒被wait後,就會進入阻塞佇列,等待下一次被喚醒, 這個涉及到執行緒間的通訊,一個執行緒執行互斥程式碼過程如下:

        1. 獲得同步鎖;

 

        2. 清空工作記憶體;

 

        3. 從主記憶體拷貝物件副本到工作記憶體;

 

        4. 執行程式碼(計算或者輸出等);

 

        5. 重新整理主記憶體資料;

 

        6. 釋放同步鎖。

        所以,synchronized既保證了多執行緒的併發有序性,又保證了多執行緒的記憶體可見性。

 

 

 

3.lock方法

Lock lc=new ReentrantLock();
lc.lock();

// do  work
lc.unlock();

這種方法一般不推薦使用

 

 

 

 

 

 

相關文章