ReadWriteLock用法

zk1878發表於2011-04-16

       物件的方法中一旦加入synchronized修飾,則任何時刻只能有一個執行緒訪問synchronized修飾的方法。假設有個資料物件擁有寫方法與讀方法,多執行緒環境中要想保證資料的安全,需對該物件的讀寫方法都要加入 synchronized同步塊。這樣任何執行緒在寫入時,其它執行緒無法讀取與改變資料;如果有執行緒在讀取時,其他執行緒也無法讀取或寫入。這種方式在寫入操作遠大於讀操作時,問題不大,而當讀取遠遠大於寫入時,會造成效能瓶頸,因為此種情況下讀取操作是可以同時進行的,而加鎖操作限制了資料的併發讀取。  

         ReadWriteLock解決了這個問題,當寫操作時,其他執行緒無法讀取或寫入資料,而當讀操作時,其它執行緒無法寫入資料,但卻可以讀取資料 。

 

        且看 以下例子

public class ReadWriteLockDemo {
	static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	public static void main(String[] args) {
		Data data = new Data();
		Worker t1 = new Worker(data,true);
		Worker t2 = new Worker(data,true);
		t1.start();
		t2.start();
	}

	static class Worker extends Thread {
		Data data;
		boolean read;

		public Worker(Data data, boolean read) {
			this.data = data;
			this.read = read;
		}

		public void run() {
			if (read)
				data.get();
			else
				data.set();
		}
	}

	static class Data {
		ReadWriteLock lock = new ReentrantReadWriteLock();
		Lock read = lock.readLock();
		Lock write = lock.writeLock();
		public  void set() {
			write.lock();
			System.out.println(Thread.currentThread().hashCode()
					+ " set:begin " + sdf.format(new Date()));
			try {
				Thread.sleep(5000);
				//
			} catch (Exception e) {

			} finally {
				System.out.println(Thread.currentThread().hashCode() + " set:end "
						+ sdf.format(new Date()));
				write.unlock();
			}
			

		}

		public  int get() {
			read.lock();
			System.out.println(Thread.currentThread().hashCode()
					+ " get :begin " + sdf.format(new Date()));
			try {
				Thread.sleep(5000);
				//
			} catch (Exception e) {

			} finally {
				System.out.println(Thread.currentThread().hashCode() + " get :end "
						+ sdf.format(new Date()));
				read.unlock();
			}
			

			return 1;
		}
	}
}

 

兩個執行緒均是讀執行緒,結果如下

 22474382 get :begin 2011-04-16 18:26:13
4699264 get :begin 2011-04-16 18:26:13
22474382 get :end 2011-04-16 18:26:18
4699264 get :end 2011-04-16 18:26:18

 

兩讀執行緒均可同時讀取資料,下面看一個是讀執行緒,一個寫執行緒的情況

Data data = new Data();
  Worker t1 = new Worker(data,false);
  Worker t2 = new Worker(data,true);
  
  t2.start();
  Thread.sleep(100);
  t1.start();

 

先啟動讀取執行緒,再啟動寫入執行緒,看結果 

14718739 get :begin 2011-04-16 18:54:46
14718739 get :end 2011-04-16 18:54:51
14737862 set:begin 2011-04-16 18:54:51
14737862 set:end 2011-04-16 18:54:56

可以看到讀取執行緒工作時,寫入執行緒是不能訪問資料的

 

 

 

 

 

相關文章