マルチスレッドの学習-ReentrantLock

同期ロックの下での暗黙的な学習の前では、特性が言うことです、悪い場所でも展示会を願っています

経験の次の要約の下ReentrantLockのを使用して、より良い同期とされてReentrantLockの程度多くのオンラインがありますが、私たちが検索することができます興味を持っているが、また、彼らの実際の状況ゾーンの選択に応じたとの協議

公式のAPIのJava 

https://docs.oracle.com/javase/8/docs/api/

ReentrantLockの特長

      1.リエントラントミューテックス 

      2.簡単に、使用する(非レベルの競技フィールドモードsynchroinzed)ロックの公正と不正競争モード、他の種類を提供します

公式推奨される使用

それがために練習をお勧めします  常に  、すぐにコールに従う  lock と  try ブロック、最も典型的には前/建設後のような:

 
 class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...
    
   public void m() {
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }

ReentrantLockの下に機能して理解することは簡単な例を見てください

public class ReentrantLockDemo {
    
    protected class MyReentrantLockRunnable implements Runnable{
        final ReentrantLock reentrantLock = new ReentrantLock(true); //采用公平竞争模式
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "就绪");
            reentrantLock.lock();//上锁
            try {
                for(int i=0;i<2;i++){
                    System.out.println(Thread.currentThread().getName() + "执行:"+i);
                }
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock(); //无论本次执行是否正常都要释放锁,以免造成死锁
            }
            System.out.println(Thread.currentThread().getName() + "完毕");
        }
    }
    
    public static void main(String[] args){
        ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
        MyReentrantLockRunnable runnable = reentrantLockDemo.new MyReentrantLockRunnable();
        Thread t1 = new Thread(runnable,"t1");
        Thread t2 = new Thread(runnable,"t2");
        t1.start();
        t2.start();
    }
}

运行结果: 

t2就绪

t1就绪

t2执行:0

t2执行:1

t2完毕

t1执行:0

t1执行:1

t1完毕  

从运行结果可以看出t2线程首先获得锁,t1进来后在门外面等t2执行完毕释放锁, 方可获得锁继续执行

ReentrantLock锁的等待和唤醒Condition 

看一个典型的生产者和消费者的例子

车间类定义

/**
 * 描述:〈食品工厂〉
 *
 * @author lyh
 * create on 2018/3/7
 * @version 1.0
 */
public class MakeFoodFactory {

    private ReentrantLock lock = new ReentrantLock(true);
    //生产者状态监听
    Condition customerCondition = lock.newCondition();
    //消费者状态监听
    Condition produceCondition = lock.newCondition();
    //工厂的最大容量 如果使用非阻塞队列效率更高
    BlockingQueue<String> blockingQueue = new LinkedBlockingDeque<>(10);

    /**
     * 消费者行为控制
     * @author lyh
     * Created On 2018/3/7 下午5:14
     */
    public void produce(){
        lock.lock();
        try {
            while (blockingQueue.size()>=3) {//当前队列中的面包数大于3的时候,暂停生产面包
                produceCondition.await();
            }
            blockingQueue.put("添加一个面包");
            System.out.println(Thread.currentThread().getName()+"生产一个面包,当前面包数"+blockingQueue.size());
            Thread.sleep(1000);
            customerCondition.signalAll(); //一旦有面包就喊一下消费者区消费   这可以优化
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 消费者行为控制
     * @author lyh
     * Created On 2018/3/7 下午5:14
     */
    public void customer(){
        try{
            lock.lock();
            while(blockingQueue.isEmpty()){  //当队列中没有面包的时候,等待
                customerCondition.await();
            }
            blockingQueue.take();
            System.out.println(Thread.currentThread().getName()+"消费一个面包,当前面包数" +blockingQueue.size());
            Thread.sleep(1000);
            produceCondition.signalAll();  //这同样也可以优化
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

生産管理ワーカークラス

/**
 * 工人生产控制
 * @author lyh
 * create on 2018/3/7
 * @version 1.0
 */
public class MakeFoodRunDemo {

    /**
     *  生产面包
     * Created On 2018/3/7 下午4:04
     */
    protected class FoodCustomer implements Runnable{
        private MakeFoodFactory makeFoodFactory;

        FoodCustomer(MakeFoodFactory makeFoodFactory){
            this.makeFoodFactory = makeFoodFactory;
        }

        @Override
        public void run() {
            for(;;){
                makeFoodFactory.customer();
            }
        }
    }
    /**
     *  消费面包
     * Created On 2018/3/7 下午4:05
     */
    protected class FoodProducer implements Runnable{
        private MakeFoodFactory makeFoodFactory;

        FoodProducer(MakeFoodFactory makeFoodFactory){
            this.makeFoodFactory = makeFoodFactory;
        }

        @Override
        public void run() {
            for(;;){
                makeFoodFactory.produce();
            }
        }
    }

    public static void main(String[] args){
        MakeFoodFactory makeFoodFactory = new MakeFoodFactory();
        MakeFoodRunDemo makeFoodRunDemo = new MakeFoodRunDemo();
        FoodProducer producer = makeFoodRunDemo.new FoodProducer(makeFoodFactory);
        FoodCustomer foodCustomer = makeFoodRunDemo.new FoodCustomer(makeFoodFactory);
        Thread t1 = new Thread(producer,"p1");
        Thread t2 = new Thread(producer,"p2");
        Thread t3 = new Thread(foodCustomer,"c1");
        t1.start();
        t2.start();
        t3.start();
    }

}

業績

p2は、食パンを製造パンの現在の数が1
p1はパンの塊を生成する、パン2の現在の数
パンのC1消費は、パンの現在の数が1
p2はパンの塊を生成する、パンの現在の数は、2
p1は食パンを製造、パン3の現在の数
、パンのC1消費パン2の現在の数
P2は、パンのローフ、パン3の現在の数生成
、パン2の現在の数パンのC1消費を
P2パンのローフ、パン3の現在の数生じる
パンのC1消費、パン2の現在の数
3、パンp2の現在の数をパンのローフ産生する
C1パンの現在の数が2つのパンの消費量は、
P2は、食パンを製造、パンは現在、数3である
パンの消費量C1、パン2の現在の数
P2は、食パンを製造、パンは現在、数3であります

パンキュー数3以上のすべての時間を見ることができるように、過ごす、消費者が費やすのを待って、シャットダウンし始め、その後、生産の上に行ってきました。生産や消費が、この状態の識別条件生産者と消費者のReentantLock状態で待機状態に条件を達成するために制御します。これは、消費者が生産を完了した後、プロデューサーは生産の条件を満たすために生産をウェイクアップした場合、すべての消費者が目覚める、または待ち続けます。

考えます:

   1.消費者がプロデューサーを起こすために持っているすべての時間は必要ではないでしょうか?

   2.生産は、それが必要ではない消費者を覚ますに行ったたびに

   3.Condition時間スレッドは()待ってロックをリリースしていませんか?

質問1と2の場合、実際には、私は2人の労働者が一緒に協力するように人生のようなプログラミングはここにあると思いますが、A1、パンを作るための責任A2は、Bは、パンを包装する責任があります。叫ぶする必要がないとき、どうやらB等の不要な通知、多くのがあるだろう(時間のために使用され、一貫した生産・包装を想定した)人物パッケージの速度よりも大きいので、真ん中の2つの生産速度が忙しい梱包されています同様に、消費者生産者が作業している叫ぶする必要はありません。これは、ように、その効率が最も高く、我々屈原漢民族であるときに我々は屈原漢彼、またA1、A2の生産に必要なときにBがパッケージに含まれていない場合は通信する必要がある真ん中です。

第三に、髪の問題

それが合図するまで、あるいは、現在のスレッドを待機させ  中断

これに関連したロックが  Condition アトミックに解除され、現在のスレッドはスレッドのスケジューリングに関して無効になり、まで待機している  1  の四つの問題が発生しました:

  • いくつかの他のスレッドが呼び出され  signal() 、この方法は  Condition 、現在のスレッドが起こされるべきスレッドとして選択することを起こります。若しくは
  • いくつかの他のスレッドが起動されます  signalAll() 。このための方法を  Condition若しくは
  • いくつかの他のスレッドは、  割り込み  現在のスレッドが、スレッド中断の割り込みがサポートされます。若しくは
  • 見せかけの起動は、」発生します。

すべての場合において、この方法の前に、この状態に関連付けられているロックを再取得する必要があり、現在のスレッドを返すことができます。スレッドが戻ったとき、されて  保証され  、このロックを保持します。

このメソッドが呼び出されると自動的にロックに関連付けられたリソースのロックを解除し、現在のスレッドになる無効状態、

我々は2つのprint文を追加します

 /**
     * 生产行为控制
     * @author lyh
     * Created On 2018/3/7 下午5:14
     */
    public void produce(){
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName()+"获得锁"+blockingQueue.size());//添加打印
            while (blockingQueue.size()>=3) {//当前队列中的面包数大于3的时候,暂停生产面包
                produceCondition.await();
                System.out.println(Thread.currentThread().getName()+"await"+blockingQueue.size());//添加打印
            }
            blockingQueue.put("添加一个面包");
            System.out.println(Thread.currentThread().getName()+"生产一个面包,当前面包数"+blockingQueue.size());
            Thread.sleep(1000);
            //if(blockingQueue.size()>=3) {
            customerCondition.signalAll(); //一旦有面包就喊一下消费者区消费
            //}
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println(Thread.currentThread().getName()+"释放锁");
            lock.unlock();

        }
    }

結果
P1 0ロック取得
p1は食パンを作る、1パンの現在の数
p1はロック解除
P2の取得がロック1
p2は食パンを作る、パン2の現在の数
P2リリースロック
パンのC1消費量は、パンの現在の数は、1
p1は1錠を得る
、p1はパンを生産しますパン2の現在の数
p1はロック解除
p2が2ロックを取得
p2は食パン、食パン3の現在の数生み出す
P2リリースロック
、パン2の現在の数パンのC1消費を
p1がロック2を取得
p1は食パン、3パンの現在の数を生成
p1はロック解除
得P2を3ロック
パンのC1消費を、パン2の現在の数
p1はロック2を取得
p1は食パン、3パンの現在の数を生成
p1はロック解除
p2await3の
パンのC1消費量を、パン2の現在の数
P1をロック2取得
p1は食パン、現在のパン番号3を生成します
P1ロック解除
p2await3の
パンのC1消費量を、パン数2現在
p1が2ロック取得
p1は食パンを作る、パンは現在、数3である
p1はロック解除
p2await3を
パンのC1消費、2パンの現在の数
p1が2ロック取得
p1は食パンを生産、現在のパン番号3
p1はロック解除
p2await3の
パンのC1消費、2パンの現在の数
p1が2ロック取得
p1は食パンを生産、現在のパン番号3
P1リリースロック
p2await3

プロセスでのP1、P2を入力するキューが、そう常に最初の実行P1、中に起こされるので、無効だったことが、この小さな公正な競争の中で見ることができ、P2、この状態では常​​に無効にしてからきっかけに目を覚ますされますP1を実行した後、キューのサイズは3となり、P2待機する必要があります。現在のスレッドが無効になった後待って、非資本政策あれば、2つのスレッドがP1、P2は、状況の出現を待つことになります

参考:

http://www.cnblogs.com/superfj/p/7543927.html 

JAVA並行プログラミング

JAVAのAPI



おすすめ

転載: blog.csdn.net/leeahuamsg/article/details/79473095