Java基礎:多線程之ReadWriteLock、Condition、Semaphore

1. ReadWriteLock

示例一:讀寫隊列

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/*
 * 讀寫鎖:分爲讀鎖和寫鎖,多個讀鎖不互斥,讀鎖與寫鎖互斥,寫鎖與寫鎖互斥,這是由JVM自己控制的,我們只需上好相應的鎖即可
 */
public class ReadWriteLockDemo {
    public static void main(String[] args){
        final MyQueue mq=new MyQueue();
        Runnable readR=new Runnable(){
            @Override
            public void run() {
                for(int i=0;i<20;i++){
                    mq.read();
                }
            }
        };

        Thread readThread1=new Thread(readR);
        Thread readThread2=new Thread(readR);

        Runnable writeR=new Runnable(){
            @Override
            public  void run() {
                for(int i=0;i<20;i++){
                    mq.write();
                }
            }

        };

        Thread writeThread1=new Thread(writeR);
        Thread writeThread2=new Thread(writeR);

        readThread1.start();
        readThread2.start();
        writeThread1.start();
        writeThread2.start();
    }
}

class MyQueue{
    private String data=null;
    private static int count=0;
    //讀寫鎖
    ReadWriteLock rwl=new ReentrantReadWriteLock();
    public void read(){
        rwl.readLock().lock();
        try{
            System.out.println();
            System.out.println(Thread.currentThread().getName()+"be ready to read...............................");
            try {
                Thread.sleep((long) (Math.random()*20));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"read data="+data);
        }finally{
            rwl.readLock().unlock();
        }
    }

    public void write(){
        rwl.writeLock().lock();
        System.out.println();
        System.out.println(Thread.currentThread().getName()+"be ready to write...............................");
        try{
            try {
                Thread.sleep((long) (Math.random()*20));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            data="this is data "+count;
            count++;
            System.out.println(Thread.currentThread().getName()+"........write data: "+data);
        }finally{
            rwl.writeLock().unlock();
        }
    }

}

示例二:緩存系統

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class CacheSystem {
    private Map<String,Object> mapCache=new HashMap<String,Object>();
    private ReadWriteLock rwl=new ReentrantReadWriteLock();

    Object getData(String key){
        rwl.readLock().lock();
        Object value=null;
        try{
            value=mapCache.get(key);

            if(value==null){
                //獲取寫鎖之前必須釋放讀鎖
                rwl.readLock().unlock();
                rwl.writeLock().lock();
                try{
                    if(value==null){
                        value="aaaaa";//實際開發中是讀數據庫
                        mapCache.put(key, value);
                    }
                }finally{
                    //鎖降級:釋放寫鎖之前,獲取讀鎖
                    rwl.readLock().lock();
                    rwl.writeLock().unlock();
                }
            }
            //使用數據:返回數據
            return value;
        }finally{
            rwl.readLock().unlock();
        }
    }
}

2. Condition

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
 * 假定有一個綁定的緩衝區,它支持 put 和 take 方法。
 * 如果試圖在空的緩衝區上執行 take 操作,則在某一個項變得可用之前,線程將一直阻塞;
 * 如果試圖在滿的緩衝區上執行 put 操作,則在有空間變得可用之前,線程將一直阻塞。
 */
public class BoundedBuffer {
       final Lock lock = new ReentrantLock();
       final Condition notFull  = lock.newCondition(); 
       final Condition notEmpty = lock.newCondition(); 

       final Object[] items = new Object[10];
       int putptr, takeptr, count;

       public void put(Object x) throws InterruptedException {
         lock.lock();
         Thread.sleep((long) (Math.random()*100));
         try {
           while (count == items.length) 
             notFull.await();
           items[putptr] = x; 
           System.out.println(Thread.currentThread().getName()+" put in position "+putptr+": "+ x);
           if (++putptr == items.length) putptr = 0;
           ++count;
           notEmpty.signal();
         } finally {
           lock.unlock();
         }
       }

       public Object take() throws InterruptedException {
         lock.lock();
         Thread.sleep((long) (Math.random()*100));
         try {
           while (count == 0) 
             notEmpty.await();
           Object x = items[takeptr]; 
           System.out.println(Thread.currentThread().getName()+" take from position "+takeptr+": "+ x+" ............");
           if (++takeptr == items.length) takeptr = 0;
           --count;
           notFull.signal();
           return x;
         } finally {
           lock.unlock();
         }
       } 

       public static void main(String[] args){
           final BoundedBuffer bb=new BoundedBuffer();
           Runnable putR=new Runnable(){
               @Override
               public void run() {
                    for(int i=0;i<20;i++){
                        try {
                            bb.put("item"+i);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
               }
           };
           Runnable takeR=new Runnable(){
               @Override
               public void run() {
                   for(int i=0;i<20;i++){
                        try {
                            bb.take();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
               }
           };

           Thread t1=new Thread(putR);
           Thread t2=new Thread(putR);
           Thread t3=new Thread(takeR);
           Thread t4=new Thread(takeR);

           t1.start();
           t2.start();
           t3.start();
           t4.start();
       }
}

3. Semaphore

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @author zj
 * 1. Semaphore可以維護當前訪問自身的線程個數,並提供了同步機制。使用Semaphore可以控制同時訪問資源的線程個數,
 *    例如,實現一個文件允許的併發訪問數。
 * 2. 單個信號量的Semaphore對象可以實現互斥鎖的功能,並且可以是由一個線程獲得了“鎖”,再由另外一個線程釋放“鎖”,
 *    這可應用於死鎖恢復的一些場合。  
 *    將信號量初始化爲 1,使得它在使用時最多隻有一個可用的許可,從而可用作一個相互排斥的鎖。這通常也稱爲二進制信號量,
 *    因爲它只能有兩種狀態:一個可用的許可,或零個可用的許可。按此方式使用時,二進制信號量具有某種屬性(與很多 Lock 實現不同),
 *    即可以由線程釋放“鎖”,而不是由所有者(因爲信號量沒有所有權的概念)。在某些專門的上下文(如死鎖恢復)中這會很有用。 
 */
public class SemaphoreDemo {
    public static void main(String[] args){
        ExecutorService threadPool=Executors.newCachedThreadPool();
        final Semaphore sp=new Semaphore(3);
        for(int i=0;i<10;i++){
            Runnable r=new Runnable(){
                @Override
                public void run() {
                    try {
                        sp.acquire();
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    System.out.println("線程"+Thread.currentThread().getName()+"已進入,當前已有"+(3-sp.availablePermits())+"個線程併發");
                    try {
                        Thread.sleep((long) (Math.random()*1000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    sp.release();
                    System.out.println("線程"+Thread.currentThread().getName()+"已經離開........當前還有"+(3-sp.availablePermits())+"個線程併發");
                }
            };
            threadPool.execute(r);
        }
        threadPool.shutdown();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章