JAVA學習筆記 -- 多線程之共享資源


在多線程程序執行過程中,可能會涉及到兩個或者多個線程試圖同一時候訪問同一個資源。為了防止這樣的情況的發生,必須在線程使用共享資源時給資源“上鎖”,以阻擋其他線程的訪問。

而這樣的機制也經常被稱為相互排斥量。本文主要介紹它的兩種方式synchronized和Lock 

1、synchronized

當任務要運行被synchronizedkeyword保護的代碼片段的時候,它會檢查鎖是否可用,然后獲取鎖。運行代碼。釋放鎖。synchronized也有兩種使用方法:

A、synchronized方法

import java.util.concurrent.*;
import java.util.*;

public class ThreadTest implements Runnable {
	public synchronized void run() { //聲明方式
		for (int i = 0; i < 5; i++) {
			System.out.println(Thread.currentThread().getName() + i);
		}
	}
	public static void main(String[] args) {
		ThreadTest t = new ThreadTest();
		Thread t1 = new Thread(t, "A");
		Thread t2 = new Thread(t, "B");
		t1.start();
		t2.start();
	}
}/*
 * Output: A0 A1 A2 A3 A4 B0 B1 B2 B3 B4
 */// :~

要注意的是,全部對象都自己主動含有單一的鎖(也稱為監視器)。所以當ThreadTest對象調用synchronized方法時,此對象被加鎖,這意味着。其它線程不能調用此對象的全部synchronized方法。 可是假設把一個復雜的方法聲明為synchronized,會減少程序執行的效率,所以synchronized塊是非常好的解決方法。

B、synchronized塊

import java.util.concurrent.*;
import java.util.*;

public class ThreadTest {
	public void g() {
		synchronized (this) { //聲明方式
			for (int i = 0; i < 5; i++) {
				System.out.println(Thread.currentThread().getName() + i);
			}
		}
	}

	public static void main(String[] args) {
		final ThreadTest t = new ThreadTest();
		Thread t1 = new Thread(new Runnable() {
			public void run() {
				t.g();
			}
		}, "A");
		Thread t2 = new Thread(new Runnable() {
			public void run() {
				t.g();
			}
		}, "B");
		t1.start();
		t2.start();
	}
}
/*
 * Output: A0 A1 A2 A3 A4 B0 B1 B2 B3 B4
 */// :~

當一個線程在訪問object對象的一個synchronized(this)同步代碼塊時,其他線程仍然能夠訪問此對象的非同步代碼塊。

當然假設不是同一個對象

,synchronized是無法實現相互排斥的。以下是第一句話的代碼:

import java.util.concurrent.*;
import java.util.*;

public class ThreadTest {
	public void g() {
		synchronized (this) {
			for (int i = 0; i < 5; i++) {
				System.out.println(Thread.currentThread().getName() + i);
			}
		}
	}

	public void h() {
		for (int i = 0; i < 5; i++) {
			System.out.println(Thread.currentThread().getName() + i);
		}
	}
	public static void main(String[] args) {
		final ThreadTest t = new ThreadTest();
		Thread t1 = new Thread(new Runnable() {
			public void run() {
				t.g();
			}
		}, "A");
		Thread t2 = new Thread(new Runnable() {
			public void run() {
				t.h();
			}
		}, "B");
		t1.start();
		t2.start();
	}
}
/*
 * Output:A0 B0 A1 B1 A2 B2 A3 B3 A4 B4
 */// :~
2、Lock 

Lock和synchronized的差別就是:

synchronized:當A和B同一時候要訪問C資源,而A獲得了對象C的鎖。B將一直等待A釋放對C的鎖,不能被中斷。

Lock:B等待一定時間后,A還不釋放C,B就會中斷等待。

它的基本使用方法:

Lock l = new ReentrantLock();
	l.lock();
	try {
	    // access the resource protected by this lock
	} finally {
	    l.unlock();
	}
從代碼也能夠看出,l.unlock()在finally{}中。這表示終於會被解鎖。

3、volatile

用volatile修飾的變量。線程在每次使用變量的時候,都會讀取變量改動后的最的值,它能避免因編譯器優化導致的讀值不准確,

然而它非常easy被誤用。

比方僅僅使用volatile變量來實現的累加器,無法得到正確結果。由於JAVA中的自增操作++,

並非原子性操作,在自增過程中還是出現了多線程間的交互。






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM