Javaのマルチスレッド-ReentrantLockリエントラントロックと共通APIを使用します

1つのReentrantLockのリエントラントロック

そして、キーワード同期はリエントラントロック操作ディスプレイと比較します。手動でロックが解除されたときに、ロックしたときに指定する必要があります。ロジック制御の柔軟性のリエントラントロックは、キーワードの同期よりもはるかに優れています。

あなたが終了すると、あなたは、ロックを解除するために覚えておく必要がありそうでない場合は、他のスレッドを訪問する機会はないだろう。

そのようなロックを繰り返し入力することができますので、リエントラントロックがリエントラントロックと呼ばれていました。しかし、唯一のスレッドの場合。

//锁定几个就要释放几个
try{
	lock.lock();	
	lock.lock()
}finally{
    lock.unlock();
    lock.unlock();
}

复制代码

使用ロック解除()メソッドを使用してロックを取得するReentrantLockのオブジェクトロック()メソッドは、ロックを解除します。

public class MyLock extends Thread{

    private Lock lock = new ReentrantLock();

    @Override
    public void run(){
        lock.lock();
        for (int i = 0;i<5;i++){
            System.out.println("ThreadName = "+Thread.currentThread().getName() + " " + i);
        }
        lock.unlock();
    }

    public static void main(String[] args) {
        MyLock myLock = new MyLock();
        Thread r = new Thread(myLock);
        Thread r1 = new Thread(myLock);
        Thread r2 = new Thread(myLock);
        r.start();r1.start();r2.start();
    }

}
复制代码

この結果から、ロック完了後の現在のスレッドの実行がリリースされる、他のスレッドは、印刷を続行することができます。コールlock.lock()メソッドは、他のスレッドがロックを待機する場合にのみ、再び戦って、「オブジェクトのモニター」を保持しているスレッドが解放されるとき。

いくつかの重要な方法をReentrantLockの:

  • ()をロック:ロック待機を占有されている場合、ロックを取得します。
  • lockInterruptibly():ロックを取得しますが、優先順位の割り込み応答。
  • tryLock():trueを返す、成功した場合、ロックを取得しようと、そうでない場合はfalseを返します。この方法は、すぐに復帰するのを待つことはありません。
  • ()ロックを解除:ロックを解除。

1.1公正かつ不公平ロックロック

公正な表示のためのスレッドがロックがスレッドを割り当てるためにロックされている取得ロック、株式及び非株式のロックにロックロックをロックし、それは、FIFO順に先着です。むしろ公正ロックのロック機構をつかむために取得する方法であるよりも、ロックは、ランダムアクセスがあり、そしてロックは、いくつかのスレッドがロックを取得することができなかった原因と、必ずしも最初のロックを取得する最初がないとフェアは同じではありません饥饿現象が。

フェアロックは良いですが、公正ロックシステムを実現することが整然としたキューを維持するため、コストが比較的高い、業績不振の公正なロックを達成する必要があります。

キーワードは非ロック同期フェアロックを生成することがあります。

あなたはロック公正公平かロックにReentrantLockののコンストラクタを指定することができます。

デフォルトで使用される非エクイティ・ロックReentrantLockの。

public class FairLock extends Thread{

    private ReentrantLock lock;

    public FairLock(boolean isFair){
        lock = new ReentrantLock(isFair);
    }

    @Override
    public void run(){
        try{
            lock.lock();
            System.out.println("⭐线程 "+ Thread.currentThread().getName() + "运行");
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        FairLock fairLock = new FairLock(true);
        Thread[] threads = new Thread[10];
        for (int i = 0;i< 10;i++){
            threads[i] = new Thread(fairLock);
        }
        Arrays.stream(threads).forEach(thread -> thread.start());
    }

}
复制代码

業績

⭐线程 Thread-1运行
⭐线程 Thread-4运行
⭐线程 Thread-3运行
⭐线程 Thread-2运行
⭐线程 Thread-5运行
⭐线程 Thread-6运行
⭐线程 Thread-7运行
⭐线程 Thread-8运行
⭐线程 Thread-9运行
⭐线程 Thread-10运行
复制代码

印刷は基本的に注文し、それが公正なロックです。falseにパラメータ場合、印刷結果は、実質的にスクランブルされています。

⭐线程 Thread-1运行
⭐线程 Thread-4运行
⭐线程 Thread-2运行
⭐线程 Thread-5运行
⭐线程 Thread-3运行
⭐线程 Thread-10运行
⭐线程 Thread-8运行
⭐线程 Thread-7运行
⭐线程 Thread-9运行
⭐线程 Thread-6运行
复制代码

1.2 getHoldCount()メソッド

ロールgetHoldCount()メソッドは、現在のスレッドがこのロックを保持していることを、コールの数がロックされている()メソッドクエリの数です。

public class MyGetHoldCount {

    private ReentrantLock lock = new ReentrantLock();
    public void serviceLock1(){
        try {
            lock.lock();
            System.out.println("serviceLock1 :" + lock.getHoldCount());
            this.serviceLock2();
        }finally {
            lock.unlock();
        }
    }

    public void serviceLock2(){
        try {
            lock.lock();
            System.out.println("serviceLock2 :" + lock.getHoldCount());
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        new MyGetHoldCount().serviceLock1();
    }
}
复制代码

プリント出力

serviceLock1 :1
serviceLock2 :2
复制代码

1.3 getQueueLength()メソッド

ロールgetQueueLength()このロックの取得を待機しているスレッドの数を返す方法。

public class MyQueueLen {
    public ReentrantLock lock = new ReentrantLock();

    public void serviceMe(){
        try {
            lock.lock();
            System.out.println("ThreadName = "+ Thread.currentThread().getName() + "获取锁");
            Thread.sleep(Integer.MAX_VALUE);
        }catch (InterruptedException e){
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyQueueLen myQueueLen = new MyQueueLen();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                myQueueLen.serviceMe();
            }
        };
        Thread[] threads = new Thread[10];
        for (int i = 0;i<10;i++){
            threads[i] = new Thread(runnable);
        }
        Arrays.stream(threads).forEach(thread -> thread.start());
        Thread.sleep(1000);
        System.out.println("有" + myQueueLen.lock.getQueueLength() + "个线程在等待锁");
    }
}
复制代码

プリント出力

ThreadName = Thread-0获取锁
有9在等待锁
复制代码

1.4 hasQueueThread()方法

ブールhasQueueThread(スレッドスレッド)の役割は、クエリ指定されたスレッドがこのロックの取得を待機しているかどうかです。

ブールhasQueueThreadsの役割は、()の任意のスレッドがこのロックの取得を待機しているかどうかを問い合わせています。

public class MyHasQTh {

    public ReentrantLock lock = new ReentrantLock();

    public void serviceMeth(){
        try{
            lock.lock();
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyHasQTh myHasQTh = new MyHasQTh();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                myHasQTh.serviceMeth();
            }
        };
        Thread threadA = new Thread(runnable);
        threadA.start();
        Thread.sleep(1000);
        Thread threadB = new Thread(runnable);
        threadB.start();
        Thread.sleep(500);
        System.out.println(myHasQTh.lock.hasQueuedThread(threadA));
        System.out.println(myHasQTh.lock.hasQueuedThread(threadB));
        System.out.println(myHasQTh.lock.hasQueuedThreads());

    }
}
复制代码

印刷結果

false
true
true
复制代码

1.5 isFai()メソッド

IsFairアクションは、()メソッドがロックを決定することで公平ではありません

public class IsFair {
    private ReentrantLock lock;
    public IsFair(boolean fair){
        lock = new ReentrantLock(fair);
    }
    public void serviceMeth(){
        try {
            lock.lock();
            System.out.println("是否是公平锁:" + lock.isFair());
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        IsFair isFair = new IsFair(true);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                isFair.serviceMeth();
            }
        };
        new Thread(runnable).start();
    }
}
复制代码

印刷結果

是否是公平锁:true
复制代码

1.6 isHeldByCurrentThread()方法

ブールisHeldByCurrentThread()メソッドの役割は、現在のスレッドがこのロックを保持するかどうかを照会することです。

public class MyHeldThread {

    private ReentrantLock lock;

    public MyHeldThread(boolean fair){
        lock = new ReentrantLock(fair);
    }

    public void serviceMethod(){
        try{
            System.out.println(lock.isHeldByCurrentThread());
            lock.lock();
            System.out.println(lock.isHeldByCurrentThread());
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        MyHeldThread myHeldThread = new MyHeldThread(true);
        new Thread(new Runnable() {
            @Override
            public void run() {
                myHeldThread.serviceMethod();
            }
        }).start();
    }
}
复制代码

印刷結果

false
true
复制代码

1.7 isLocked()方法

ブールisLocked()メソッドの役割は、任意のスレッドによって保持され、このロックを照会することです。

public class MyIsLocked {

    public ReentrantLock lock = new ReentrantLock();

    public void serviceMethod(){
        try{
            System.out.println(lock.isLocked());
            lock.lock();
            System.out.println(lock.isLocked());
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        MyIsLocked myIsLocked = new MyIsLocked();
        new Thread(new Runnable() {
            @Override
            public void run() {
                myIsLocked.serviceMethod();
            }
        }).start();
    }
}
复制代码

印刷結果

false
true
复制代码

1.8のtryLock()メソッド

ロックがfalseを返すために保持されている場合ブールのtryLock()メソッドは、ロックがケースの別のスレッドによって保持されていない場合にのみ呼び出されるの役割は、真を返します。そしてすぐに、待っていない実行されます。

tryLockはセルフロックを防止するための重要な方法です。

public class MyTryLock {

    public ReentrantLock lock = new ReentrantLock();

    public void serviceMethod(){
        try {
            if (lock.tryLock()) {
                System.out.println(Thread.currentThread().getName() + "获取锁定 "+System.currentTimeMillis());
                Thread.sleep(4000);
            } else {
                System.out.println(Thread.currentThread().getName() + "未获取锁定");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        MyTryLock myTryLock = new MyTryLock();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                myTryLock.serviceMethod();
            }
        };
        Thread aa = new Thread(runnable, "aa");
        aa.start();
        Thread bb = new Thread(runnable, "bb");
        bb.start();
    }
}

复制代码

印刷結果:

aa未获取锁定
bb获取锁定 1560237476296
复制代码

ロックが与えられた待機時間内に別のスレッドによって保持されていないと、現在のスレッドが中断されていない場合はブールのtryLock(長いタイムアウト、TimeUnitでユニット)の役割は、ロックを取得します。

指定された時間内にロックを取得するために待機。

public class MyTryLock {

    public ReentrantLock lock = new ReentrantLock();

    public void serviceMethod(){
        try {
            if (lock.tryLock(3,TimeUnit.SECONDS)) {
                System.out.println(Thread.currentThread().getName() + "获取锁定 "+System.currentTimeMillis());
                Thread.sleep(2000);
            } else {
                System.out.println(Thread.currentThread().getName() + "未获取锁定");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        MyTryLock myTryLock = new MyTryLock();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " " + System.currentTimeMillis());
                myTryLock.serviceMethod();
            }
        };
        Thread aa = new Thread(runnable, "aa");
        aa.start();
        Thread bb = new Thread(runnable, "bb");
        bb.start();
    }
}
复制代码

印刷結果:

aa 1560237873563
bb 1560237873563
bb获取锁定 1560237873563
aa获取锁定 1560237875579
复制代码

3秒以上の時間へのThread.sleepコード()した場合は、印刷されています。

aa 1560237942950
bb 1560237942950
bb获取锁定 1560237942950
aa未获取锁定
复制代码

1.9 getWaitQueueLength()方法

役割はint getWaitQueueLength(条件CON)メソッドは、この条件が与えられているに関連付けられたロックを待っているスレッドの数を返すことです。つまり、このロックを待っている状態で、指定されたインスタンスの数です。

public class MyWaitQuere {

    public ReentrantLock lock = new ReentrantLock();
    public Condition con = lock.newCondition();

    public void waitMethod(){
        try{
            lock.lock();
            con.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void signalMethod(){
        try{
            lock.lock();
            System.out.println("有 " + lock.getWaitQueueLength(con) + "个线程正在等待con");
            con.signal();
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyWaitQuere myWaitQuere = new MyWaitQuere();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                myWaitQuere.waitMethod();
            }
        };
        Thread[] threads = new Thread[10];
        for(int i = 0;i< 10;i++){
            threads[i] = new Thread(runnable);
        }
        Arrays.stream(threads).forEach(thread -> thread.start());
        Thread.sleep(2000);
        myWaitQuere.signalMethod();
    }
}
复制代码

印刷結果

有 10个线程正在等待con
复制代码

1.10 int型hasWaiters(条件CON)

ロールint型hasWaiters(条件CON)の任意のスレッドがこの条件ロックに関連付けられた条件を待っているかどうかを問い合わせています。

public class MyHasWaiters {

    public ReentrantLock lock = new ReentrantLock();
    public Condition con = lock.newCondition();
    public void myWait(){
        try{
            lock.lock();
            con.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    public void hasWaits(){
        try{
            lock.lock();
            System.out.println("是否有线程在等待con : " + lock.hasWaiters(con));
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyHasWaiters myHasWaiters = new MyHasWaiters();
        new Thread(new Runnable() {
            @Override
            public void run() {
                myHasWaiters.myWait();
            }
        }).start();
        Thread.sleep(2000);
        myHasWaiters.hasWaits();
    }
}
复制代码

印刷結果

是否有线程在等待con : true
复制代码

1.11 lockInterruptibly()方法

役割のボイドlockInterruptibly()メソッドは、中断された現在のスレッドが例外をスローし、その後、ロックを取得中断されていない場合ということです。

public class MyLockInterr {

    public ReentrantLock lock = new ReentrantLock();
    public void waitMethod(){
        try{
            lock.lockInterruptibly();
            System.out.println("lock begin " + Thread.currentThread().getName());
            for (int i = 0;i< Integer.MAX_VALUE;i++){new String();}
            System.out.println("lock end " + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()){
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyLockInterr myLockInterr = new MyLockInterr();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                myLockInterr.waitMethod();
            }
        };
        Thread aaa = new Thread(runnable, "aaa");
        Thread bbb = new Thread(runnable, "bbb");
        aaa.start();
        Thread.sleep(500);
        bbb.start();
        bbb.interrupt();
        System.out.println("main end");
    }
}
复制代码

印刷結果

lock begin aaa
lock end aaa
java.lang.InterruptedException
main end
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1220)
	at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
	at com.wtj.lock.MyLockInterr.waitMethod(MyLockInterr.java:16)
	at com.wtj.lock.MyLockInterr$1.run(MyLockInterr.java:34)
	at java.lang.Thread.run(Thread.java:748)
复制代码

lock.lockInterruptiblyは()の代わりに()lock.lock場合はエラーではありません。

2の条件は、待機/通知を達成します

同期、(待機)、及びnotfiy()/のnotifyAll()メソッドを達成することができるウェイト/通知モード基づいてReentrantLockの同様の機能と組み合わせて実施することができるが、このようなマルチチャネル通知などのオブジェクトの状態、条件、より良い柔軟性を使用する必要スレッドが選択、スケジューリングをより柔軟に通知ができるようにし、他の機能は、複数の条件(すなわちオブジェクトモニター)インスタンスを作成することができますロックオブジェクトである、スレッド・オブジェクトは、指定された条件で登録することができます。

条件の唯一の単一のインスタンスオブジェクト全体に相当するものをロックし、同期、すべてのスレッドがこの1つのインスタンスに登録されています。

await()メソッドを使用して、条件クラスは、ロック電流を放出しながらスレッドが待つことができます。信号()ウェイクアップ方法を使用。

条件のインスタンスを使用する前に方法がロックされたままにする必要があります。Lock.lock()

複数のスレッド通知部を使用した状態の実装

public class MyCondition {

    private ReentrantLock lock = new ReentrantLock();
    private Condition con1 = lock.newCondition();
    private Condition con2 = lock.newCondition();

    public void await1(){
        try{
            lock.lock();
            System.out.println("await1 start : "+ System.currentTimeMillis() + " " + Thread.currentThread().getName());
            con1.await();
            System.out.println("await1 end : "+ System.currentTimeMillis() + " " + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void await2(){
        try{
            lock.lock();
            System.out.println("await2 start : "+ System.currentTimeMillis() + " " + Thread.currentThread().getName());
            con2.await();
            System.out.println("await2 end : "+ System.currentTimeMillis() + " " + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void signalAll_1(){
        try{
            lock.lock();
            System.out.println("signalAll_1 start : "+ System.currentTimeMillis() + " " + Thread.currentThread().getName());
            con1.signalAll();
        }finally {
            lock.unlock();
        }
    }

    public void signalAll_2(){
        try{
            lock.lock();
            System.out.println("signalAll_2 start : "+ System.currentTimeMillis() + " " + Thread.currentThread().getName());
            con2.signalAll();
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyCondition myCondition = new MyCondition();
        new Thread(new Runnable() {
            @Override
            public void run() {
                myCondition.await1();
            }
        }, "aaa").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                myCondition.await2();
            }
        },"bbb").start();
        Thread.sleep(3000);
        myCondition.signalAll_1();
    }
}
复制代码

印刷結果

await1 start : 1560238945661 aaa
await2 start : 1560238945661 bbb
signalAll_1 start : 1560238948666 main
await1 end : 1560238948666 aaa
复制代码

出力結果から、唯一のスレッドのAAAを目覚めさせられます。

3 ReentrantReadWriteLock类

同時に1つのスレッドしかロック()メソッドの後にタスクを実行するために、その完全な相互排他効果とReentrantLockのクラス、。これは、スレッドセーフを保証することができますが、効率が非常に低いですが。

ReentrantReadWriteLock JDKが動作効率をスピードアップすることができるクラスを、提供され、この方法は、読み書きロックが効率ReentrantReadWriteLockクラスを改善するために使用することができる、いくつかのインスタンス変数で動作する必要はありません。

読み書きロックReentrantReadWriteLockは、2つのロックを持っている、ロックも呼ばれる、読み出し動作に関連付けられている共有ロック、書き込み動作はまたとして知られている、ロックを関連付けられている排他ロックより多くのではない相互に排他的ロック、排他的な書き込みロックを読み、ロックを読んで、ロックを書いて、書き込みロックは相互に排他的です

3.1読むシェア

public class MyReadLock {

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public void read(){
        try{
            lock.readLock().lock();     //读锁锁定
            System.out.println("获取读锁" + Thread.currentThread().getName()+ " "+ System.currentTimeMillis());
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.readLock().unlock();
        }
    }

    public static void main(String[] args) {
        MyReadLock myReadLock = new MyReadLock();
        new Thread(new Runnable() {
            @Override
            public void run() {
                myReadLock.read();
            }
        },"aaa").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                myReadLock.read();
            }
        },"bbb").start();
    }
}
复制代码

印刷結果

获取读锁aaa 1560241121534
获取读锁bbb 1560241121534
复制代码

同時にロック()コード方式に二つのスレッドの結果から分かるように、説明ロックが複数のスレッドが同時にロック()コード方式を実行することを可能に読み取ります。

3.2相互に排他的で書きます

public class MyWriteLock {

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public void write(){
        try{
            lock.writeLock().lock();        //写锁锁定
            System.out.println("获得写锁"+ Thread.currentThread().getName() + " " + System.currentTimeMillis());
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.writeLock().unlock();
        }
    }

    public static void main(String[] args) {
        MyWriteLock myWriteLock = new MyWriteLock();
        new Thread(new Runnable() {
            @Override
            public void run() {
                myWriteLock.write();
            }
        },"aaa").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                myWriteLock.write();
            }
        },"bbb").start();
    }
}
复制代码

印刷結果

获得写锁aaa 1560241405832
获得写锁bbb 1560241409834
复制代码

それが同時にロックが後に一つだけスレッド実行ロック()メソッドを可能にする書き込み指示、入力する前に、スレッドのAAA BBBスレッドを実行するために4秒後に見ることができます。

3.3ロックミューテックスを読みます

public class MyReadWriteLock {

    public ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public void read(){
        try{
            lock.readLock().lock();
            System.out.println("获取读锁 " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.readLock().unlock();
        }
    }
    public void write(){
        try{
            lock.writeLock().lock();
            System.out.println("获取写锁 " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.writeLock().unlock();
        }
    }

    public static void main(String[] args) {
        MyReadWriteLock myReadWriteLock = new MyReadWriteLock();
        new Thread(new Runnable() {
            @Override
            public void run() {
                myReadWriteLock.read();
            }
        },"aaa").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                myReadWriteLock.write();
            }
        },"bbb").start();
    }
}
复制代码

印刷結果

获取读锁 aaa 1560241741764
获取写锁 bbb 1560241745770
复制代码

ます。https://juejin.im/post/5d075878518825710d2b2471で再現

おすすめ

転載: blog.csdn.net/weixin_34101784/article/details/93174275