線程鎖技術

  Lock比傳統線程模型中的synchronized方式更加面向對象,與生活中的鎖類似,鎖本身也應該是一個對象。兩個線程執行的代碼片段要實現同步互斥的效果,他們必須用同一個Lock對象,鎖是上在代表要操作的資源的類的內部方法中,而不是線程代碼中。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
public class LockTest {
 
   public static void main(String[] args) {
      new LockTest().init();
   }
  
   public void init(){
      Outputer outputer = new Outputer();
      new Thread(new Runnable(){
 
         @Override
         public void run() {
            while(true){
                try {
                   Thread.sleep(10);
                } catch (InterruptedException e) {
                   e.printStackTrace();
                }
                outputer.output("zhangxiaoxiang");
            }
         }
        
      }).start();
     
      new Thread(new Runnable(){
 
         @Override
         public void run() {
            while(true){
                try {
                   Thread.sleep(10);
                } catch (InterruptedException e) {
                   e.printStackTrace();
                }
                outputer.output("liwenfei");
            }
         }
        
      }).start();
   }
  
   /**
    * 會出現線程安全的問題
    *
    */
 /* class Outputer{
      public void output(String name){
         int len = name.length();
         for(int i=0; i<len; i++){
            System.out.print(name.charAt(i));
         }
         System.out.println();//換行
      }
   }*/
  
   static class Outputer{
      Lock lock = new ReentrantLock();
      public void output(String name){
         int len = name.length();
         lock.lock();
         try{//使用try是確保裏邊的代碼不管有沒有出錯,最後都要打開鎖
            for(int i=0; i<len; i++){
                System.out.print(name.charAt(i));
            }
            System.out.println();//換行
         }finally{
            lock.unlock();
         }
      }
     
      /**
       * 方法二:把要同步的代碼所在方法全部同步
       * 在方法上使用synchronized後不要在內部再使用synchronized,不然很容易出現死鎖
       */
      public synchronized void output2(String name){
         int len = name.length();
         for(int i=0; i<len; i++){
            System.out.print(name.charAt(i));
         }
         System.out.println();//換行
      }
     
      /**
       * 如果這個同步方法是static的,那麼爲了確保不管誰調用同步方法,鎖對象是同一個,
       * 那麼鎖只能爲當前類的字節碼對象,即Outputer.class
       * @param name
       */
      public static synchronized void output3(String name){
         int len = name.length();
         for(int i=0; i<len; i++){
            System.out.print(name.charAt(i));
         }
         System.out.println();//換行
      }
   }
  
}
Lock分爲讀鎖和寫鎖,多個讀鎖不互斥,讀鎖與寫鎖互斥,寫鎖與寫鎖互斥。這是由jvm自己控制的,你只要上好相應的鎖即可。如果你的代碼只讀數據,可以很多人同時讀,但不能同時寫,那就上讀鎖;如果你的代碼修改數據,只能有一個人在寫,且不能同時讀數據,那就上寫鎖。總之讀的時候上讀鎖,寫的時候上寫鎖。提高性能。
import java.util.Random;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockTest {
	public static void main(String[] args) {
		final Queue3 q3 = new Queue3();
		for (int i = 0; i < 3; i++) {
			new Thread() {
				@Override
				public void run() {
					while (true) {
						q3.get();
					}
				}
			}.start();
			new Thread() {
				public void run() {
					while (true) {
						q3.put(new Random().nextInt(10000));
					}
				};
			}.start();
		}
	}
}

class Queue3 {
	private Object data = null; // 共享數據,只能又一個線程能寫該數據,但是可以有多個線程可以讀
	private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

	public void get() {
		rwl.readLock().lock();
		try {
			System.out.println(Thread.currentThread().getName() + " be ready to read data!");
			Thread.sleep((long) (Math.random() * 1000));
			System.out.println(Thread.currentThread().getName() + " hava read data : " + data);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			rwl.readLock().unlock(); // 使用finally不管出現什麼意外,一定要將鎖釋放掉
		}
	}

	public void put(Object data) {
		rwl.writeLock().lock();
		try {
			System.out.println(Thread.currentThread().getName() + " be ready to write data!");
			Thread.sleep((long) (Math.random() * 1000));
			this.data = data;
			System.out.println(Thread.currentThread().getName() + " hava writed data : " + data);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			rwl.writeLock().unlock();
		}
	}
}

在jdk api java.util.concurrent.locks.ReentrantReadWriteLock類中有個緩存器設計的僞代碼示例:
 class CachedData {
   Object data;
   volatile boolean cacheValid;
   ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

   void processCachedData() {
     rwl.readLock().lock();
     if (!cacheValid) {
        // Must release read lock before acquiring write lock
        rwl.readLock().unlock();
        rwl.writeLock().lock();
        // Recheck state because another thread might have acquired
        //   write lock and changed state before we did.
        if (!cacheValid) {
          data = ...
          cacheValid = true;
        }
        // Downgrade by acquiring read lock before releasing write lock
        rwl.readLock().lock();
        rwl.writeLock().unlock(); // Unlock write, still hold read
     }

     use(data);
     rwl.readLock().unlock();
   }
 }

緩存的思想:

 












發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章