Java多線程編程(四)Lock的使用

  1、使用ReentrantLock類java

  在Java多線程中,可使用synchronized關鍵字來實現線程之間的同步互斥,但ReentrantLock類也能達到一樣的效果,而且在擴展功能上也更增強大,好比具備嗅探鎖定、多路分支通知等功能,並且在使用上也比synchronized更加的靈活。安全

  1.使用ReentrantLock實現同步:測試1多線程

  示例:從運行的結果來看,是同步運行的,即當前線程打印完畢以後將鎖進行釋放,其餘線程才能夠繼續打印。線程打印的數據是分組打印的,由於當前線程已經持有鎖,但線程之間打印的順序是隨機的。dom

package service;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    private Lock lock = new ReentrantLock();

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

}
package extthread;

import service.MyService;

public class MyThread extends Thread {

    private MyService service;

    public MyThread(MyService service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.testMethod();
    }
}
package test;

import service.MyService;
import extthread.MyThread;

public class Run {

    public static void main(String[] args) {

        MyService service = new MyService();

        MyThread a1 = new MyThread(service);
        MyThread a2 = new MyThread(service);
        MyThread a3 = new MyThread(service);
        MyThread a4 = new MyThread(service);
        MyThread a5 = new MyThread(service);

        a1.start();
        a2.start();
        a3.start();
        a4.start();
        a5.start();

    }

}
ThreadName=Thread-0 1
ThreadName=Thread-0 2
ThreadName=Thread-0 3
ThreadName=Thread-0 4
ThreadName=Thread-0 5
ThreadName=Thread-2 1
ThreadName=Thread-2 2
ThreadName=Thread-2 3
ThreadName=Thread-2 4
ThreadName=Thread-2 5
ThreadName=Thread-1 1
ThreadName=Thread-1 2
ThreadName=Thread-1 3
ThreadName=Thread-1 4
ThreadName=Thread-1 5
ThreadName=Thread-3 1
ThreadName=Thread-3 2
ThreadName=Thread-3 3
ThreadName=Thread-3 4
ThreadName=Thread-3 5
ThreadName=Thread-4 1
ThreadName=Thread-4 2
ThreadName=Thread-4 3
ThreadName=Thread-4 4
ThreadName=Thread-4 5

  2.使用ReentrantLock實現同步:測試2ide

  示例:線程A和AA爲一組,執行方法a,線程B和BB爲一組,執行方法b。從結果能夠看出,調用lock.lock();代碼的線程就持有了「對象監視器」,其餘線程只有等待鎖被釋放時再次爭搶。效果和使用synchronized同樣,線程之間仍是順序執行的。學習

package extthread;

import service.MyService;

public class ThreadA extends Thread {

    private MyService service;

    public ThreadA(MyService service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.methodA();
    }
}
package service;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    private Lock lock = new ReentrantLock();

    public void methodA() {
        try {
            lock.lock();
            System.out.println("methodA begin ThreadName="+ Thread.currentThread().getName() 
                             + " time="+ System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("methodA  end ThreadName="+ Thread.currentThread().getName() 
                             + " time="+ System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void methodB() {
        try {
            lock.lock();
            System.out.println("methodB begin ThreadName="+ Thread.currentThread().getName() 
                             + " time="+ System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("methodB  end ThreadName="+ Thread.currentThread().getName() 
                             + " time="+ System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}
package test;

import service.MyService;
import extthread.ThreadA;
import extthread.ThreadAA;
import extthread.ThreadB;
import extthread.ThreadBB;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();

        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        
        ThreadAA aa = new ThreadAA(service);
        aa.setName("AA");
        aa.start();

        Thread.sleep(100);

        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();
        
        ThreadBB bb = new ThreadBB(service);
        bb.setName("BB");
        bb.start();

    }

}
methodA begin ThreadName=A time=1525674628430
methodA  end ThreadName=A time=1525674633431
methodA begin ThreadName=AA time=1525674633432
methodA  end ThreadName=AA time=1525674638436
methodB begin ThreadName=B time=1525674638436
methodB  end ThreadName=B time=1525674643443
methodB begin ThreadName=BB time=1525674643443
methodB  end ThreadName=BB time=1525674648443

  3.使用Condition實現等待/通知錯誤用法與解決測試

  Condition類能夠用來實現多路通知功能,也就是在一個Lock對象裏面能夠建立多個Condition實例,線程對象能夠註冊在指定的Condition中,從而能夠有選擇性地進行線程通知,在調度線程上更加靈活。synchronized就至關於整個Lock對象中只有一個單一的Condition對象,全部的線程都註冊在它一個對象的身上。ui

  示例1:出現異常的緣由是監視器出錯,解決的辦法是必須在condition.await()方法調用以前調用lock.lock()代碼取得同步監視器。this

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void await() {
        try {
            condition.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package extthread;

import service.MyService;

public class ThreadA extends Thread {

    private MyService service;

    public ThreadA(MyService service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.await();
    }
}
package test;

import service.MyService;
import extthread.ThreadA;

public class Run {

    public static void main(String[] args) {

        MyService service = new MyService();

        ThreadA a = new ThreadA(service);
        a.start();

    }

}
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
	at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.fullyRelease(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(Unknown Source)
	at service.MyService.await(MyService.java:14)
	at extthread.ThreadA.run(ThreadA.java:16)

   示例2:修改await()方法,輸出只打印了一個A,說明了condition.await();方法使當前執行任務的線程進入了等待狀態,在lock.unlock();釋放鎖後才能夠繼續執行。spa

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void waitMethod() {
        try {
            lock.lock();
            System.out.println("A");
            condition.await();
            System.out.println("B");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            System.out.println("鎖被釋放了!");
        }
    }
}
A

  4.正確使用Condition實現等待/通知

  示例:從輸出結果能夠看出,使用condition.await();condition.signal();成功實現了等待/通知模式。

  和以前的wait/notify作對比:

  Object類中的wait()方法--------Condition類中的await()方法

  Object類中的wait(long)方法--Condition類中的await(long)方法

  Object類中的notify()方法-------Condition類中的signal()方法

  Object類中的notifyAll()方法---Condition類中的signalAll()方法

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    private Lock lock = new ReentrantLock();
    public Condition condition = lock.newCondition();

    public void await() {
        try {
            lock.lock();
            System.out.println(" await打印時間:" + System.currentTimeMillis());
            condition.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void signal() {
        try {
            lock.lock();
            System.out.println("signal打印時間:" + System.currentTimeMillis());
            condition.signal();
        } finally {
            lock.unlock();
        }
    }
}
package extthread;

import service.MyService;

public class ThreadA extends Thread {

    private MyService service;

    public ThreadA(MyService service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.await();
    }
}
package test;

import service.MyService;
import extthread.ThreadA;

public class Run {

    public static void main(String[] args) throws InterruptedException {

        MyService service = new MyService();

        ThreadA a = new ThreadA(service);
        a.start();

        Thread.sleep(3000);

        service.signal();

    }

}
 await打印時間:1525675563292
signal打印時間:1525675566292

  5.使用多個Condition實現通知部分線程:錯誤用法

  示例:程序運行後,因爲使用了service.signalAll();而signalAll()方法中使用了condition.signalAll();因此使線程A和線程B都被喚醒了,(若是將condition.signalAll();修改爲condition.signal();那麼只能隨機有一個線程被喚醒,經過屢次輸出發現線程B一直都不會被喚醒。若是想單獨喚醒部分線程,就有必要使用多個Condition對象了,也就是Condition對象能夠喚醒部分指定線程,有助於提高程序運行的效率。能夠先對線程進行分組,而後再喚醒執行組中的線程。

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    private Lock lock = new ReentrantLock();
    public Condition condition = lock.newCondition();

    public void awaitA() {
        try {
            lock.lock();
            System.out.println("begin awaitA time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
            condition.await();
            System.out.println("  end awaitA time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void awaitB() {
        try {
            lock.lock();
            System.out.println("begin awaitB time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
            condition.await();
            System.out.println("  end awaitB time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void signalAll() {
        try {
            lock.lock();
            System.out.println("  signalAll time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }
}
package extthread;

import service.MyService;

public class ThreadA extends Thread {

    private MyService service;

    public ThreadA(MyService service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.awaitA();
    }
}
package extthread;

import service.MyService;

public class ThreadB extends Thread {

    private MyService service;

    public ThreadB(MyService service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.awaitB();
    }
}
package test;

import service.MyService;
import extthread.ThreadA;
import extthread.ThreadB;

public class Run {

    public static void main(String[] args) throws InterruptedException {

        MyService service = new MyService();

        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();

        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();

        Thread.sleep(3000);

        service.signalAll();

    }

}
begin awaitA time1525676214892 ThreadName=A
begin awaitB time1525676214892 ThreadName=B
   signalAll time1525676217896 ThreadName=main
  end awaitA time1525676217896 ThreadName=A
  end awaitB time1525676217896 ThreadName=B

  6.使用多個Condition實現通知部分線程:正確用法

  示例:修改MyService.java建立多個Condition對象,main方法中只喚醒A線程。從輸出結果來看,確實只喚醒了一個指定的線程A線程。

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    private Lock lock = new ReentrantLock();
    public Condition conditionA = lock.newCondition();
    public Condition conditionB = lock.newCondition();

    public void awaitA() {
        try {
            lock.lock();
            System.out.println("begin awaitA time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
            conditionA.await();
            System.out.println("  end awaitA time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void awaitB() {
        try {
            lock.lock();
            System.out.println("begin awaitB time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
            conditionB.await();
            System.out.println("  end awaitB time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void signalAll_A() {
        try {
            lock.lock();
            System.out.println("  signalAll_A time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
            conditionA.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public void signalAll_B() {
        try {
            lock.lock();
            System.out.println("  signalAll_B time" + System.currentTimeMillis()
                    + " ThreadName=" + Thread.currentThread().getName());
            conditionB.signalAll();
        } finally {
            lock.unlock();
        }
    }
}
package test;

import service.MyService;
import extthread.ThreadA;
import extthread.ThreadB;

public class Run {

    public static void main(String[] args) throws InterruptedException {

        MyService service = new MyService();

        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();

        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();

        Thread.sleep(3000);

        service.signalAll_A();

    }

}
begin awaitA time1525676857516 ThreadName=A
begin awaitB time1525676857516 ThreadName=B
 signalAll_A time1525676860517 ThreadName=main
  end awaitA time1525676860517 ThreadName=A

  7.實現生產者/消費者模式:一對一交替打印

  示例:和前面學習過的wait/notify實現一對一交替打印的原理同樣,經過改變hasValue的值來實現。從輸出結果能夠看出,使用Condition對象成功地實現了交替打印的效果。

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    private boolean hasValue = false;

    public void set() {
        try {
            lock.lock();
            while (hasValue == true) {
                condition.await();
            }
            System.out.println("打印set");
            hasValue = true;
            condition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void get() {
        try {
            lock.lock();
            while (hasValue == false) {
                condition.await();
            }
            System.out.println("打印get");
            hasValue = false;
            condition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}
package extthread;

import service.MyService;

public class MyThreadA extends Thread {

    private MyService myService;

    public MyThreadA(MyService myService) {
        super();
        this.myService = myService;
    }

    @Override
    public void run() {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            myService.set();
        }
    }

}
package extthread;

import service.MyService;

public class MyThreadB extends Thread {

    private MyService myService;

    public MyThreadB(MyService myService) {
        super();
        this.myService = myService;
    }

    @Override
    public void run() {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            myService.get();
        }
    }

}
package test;

import service.MyService;
import extthread.MyThreadA;
import extthread.MyThreadB;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        MyService myService = new MyService();

        MyThreadA a = new MyThreadA(myService);
        a.start();

        MyThreadB b = new MyThreadB(myService);
        b.start();

    }
}
打印set
打印get
打印set
打印get
打印set
打印get
打印set
打印get
打印set
打印get
打印set
打印get
打印set
打印get
...

  8.實現生產者/消費者模式:多對多交替打印

  示例1:修改MyService類和Run類。從輸出能夠看出,程序運行後出現了「假死」,不能一直運行下去,出現的緣由和以前的notify()不是notifyAll()同樣。

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    private boolean hasValue = false;

    public void set() {
        try {
            lock.lock();
            while (hasValue == true) {
                System.out.println("hasValue值爲true");
                condition.await();
            }
            System.out.println("打印set");
            hasValue = true;
            condition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void get() {
        try {
            lock.lock();
            while (hasValue == false) {
                System.out.println("hasValue值爲false");
                condition.await();
            }
            System.out.println("打印get");
            hasValue = false;
            condition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}
package test;

import service.MyService;
import extthread.MyThreadA;
import extthread.MyThreadB;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();

        MyThreadA[] threadA = new MyThreadA[10];
        MyThreadB[] threadB = new MyThreadB[10];

        for (int i = 0; i < 10; i++) {
            threadA[i] = new MyThreadA(service);
            threadB[i] = new MyThreadB(service);
            threadA[i].start();
            threadB[i].start();
        }

    }
}
打印set
hasValue值爲true
打印get
hasValue值爲false
打印set
hasValue值爲true
打印get
hasValue值爲false
打印set
hasValue值爲true
打印get
hasValue值爲false
打印set
hasValue值爲true
打印get
hasValue值爲false
打印set
hasValue值爲true
hasValue值爲true
打印get
hasValue值爲false
hasValue值爲false
hasValue值爲false
打印set
hasValue值爲true
hasValue值爲true
hasValue值爲true
打印get
hasValue值爲false
打印set
hasValue值爲true
hasValue值爲true
打印get
hasValue值爲false
hasValue值爲false
打印set
hasValue值爲true
打印get
hasValue值爲false
hasValue值爲false
打印set
hasValue值爲true
打印get
hasValue值爲false
打印set
hasValue值爲true
hasValue值爲true
打印get
hasValue值爲false
打印set
hasValue值爲true
hasValue值爲true
hasValue值爲true
打印get
hasValue值爲false
打印set
hasValue值爲true
hasValue值爲true
打印get
hasValue值爲false
hasValue值爲false
hasValue值爲false
打印set
hasValue值爲true
打印get
hasValue值爲false
hasValue值爲false
打印set
hasValue值爲true
打印get
hasValue值爲false
hasValue值爲false
打印set
hasValue值爲true
打印get
hasValue值爲false
打印set
hasValue值爲true
hasValue值爲true
打印get
hasValue值爲false
打印set
hasValue值爲true
hasValue值爲true
hasValue值爲true

   示例2:修改爲signalAll()後,程序能夠一直運行下去,再也不出現「假死」的現象,set和get是交替輸出的,可是true和false卻不是交替輸出的,這是由於程序中使用了同一個Condition對象,在結合signalAll()方法喚醒全部的線程,那麼喚醒的線程就有多是同類,所以就出現了不是交替輸出的狀況。

打印set
hasValue值爲true
hasValue值爲true
hasValue值爲true
hasValue值爲true
打印get
hasValue值爲false
hasValue值爲false
hasValue值爲false
hasValue值爲false
hasValue值爲false
hasValue值爲false
hasValue值爲false
hasValue值爲false
打印set
hasValue值爲true
hasValue值爲true
hasValue值爲true
hasValue值爲true
打印get
hasValue值爲false
打印set
hasValue值爲true
hasValue值爲true
打印get
hasValue值爲false
打印set
hasValue值爲true
hasValue值爲true
hasValue值爲true
hasValue值爲true
打印get
hasValue值爲false
hasValue值爲false
hasValue值爲false
hasValue值爲false
hasValue值爲false
hasValue值爲false
hasValue值爲false
hasValue值爲false
...

  9.公平鎖與非公平鎖

  鎖Lock分爲「公平鎖」和「非公平鎖」,公平鎖表示線程獲取鎖的順序是按照線程加鎖的順序來分配的,即先來先得的FIFO先進先出順序。而非公平鎖就是一種獲取鎖的搶佔機制,是隨機得到鎖的,和公平鎖不同的就是先來的不必定先獲得鎖,這個方式可能形成某些線程一直拿不到鎖,結果也就是不公平的了。

  示例1:公平鎖的測試類。lock = new ReentrantLock(isFair);中isFair設置爲true,打印的結果基本是呈有序的狀態。

package service;

import java.util.concurrent.locks.ReentrantLock;

public class Service {

    private ReentrantLock lock;

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

    public void serviceMethod() {
        try {
            lock.lock();
            System.out.println("ThreadName=" + Thread.currentThread().getName()
                    + "得到鎖定");
        } finally {
            lock.unlock();
        }
    }

}
package test.run;

import service.Service;

public class RunFair {

    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service(true);

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("★線程" + Thread.currentThread().getName()
                        + "運行了");
                service.serviceMethod();
            }
        };

        Thread[] threadArray = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threadArray[i] = new Thread(runnable);
        }
        for (int i = 0; i < 10; i++) {
            threadArray[i].start();
        }

    }
}
★線程Thread-2運行了
★線程Thread-0運行了
★線程Thread-1運行了
ThreadName=Thread-0得到鎖定
★線程Thread-3運行了
★線程Thread-5運行了
★線程Thread-7運行了
ThreadName=Thread-1得到鎖定
★線程Thread-6運行了
ThreadName=Thread-2得到鎖定
ThreadName=Thread-3得到鎖定
ThreadName=Thread-5得到鎖定
★線程Thread-4運行了
ThreadName=Thread-7得到鎖定
ThreadName=Thread-6得到鎖定
ThreadName=Thread-4得到鎖定
★線程Thread-8運行了
ThreadName=Thread-8得到鎖定
★線程Thread-9運行了
ThreadName=Thread-9得到鎖定

   示例2:非公平鎖的測試類。lock = new ReentrantLock(isFair);中isFair設置爲false,打印的結果基本是呈亂序的狀態,說明先start()啓動的線程不表明先得到鎖。

package test.run;

import service.Service;

public class RunNotFair {

    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service(false);

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("★線程" + Thread.currentThread().getName()
                        + "運行了");
                service.serviceMethod();
            }
        };

        Thread[] threadArray = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threadArray[i] = new Thread(runnable);
        }
        for (int i = 0; i < 10; i++) {
            threadArray[i].start();
        }

    }
}
★線程Thread-0運行了
★線程Thread-1運行了
ThreadName=Thread-1得到鎖定
ThreadName=Thread-0得到鎖定
★線程Thread-2運行了
★線程Thread-3運行了
ThreadName=Thread-3得到鎖定
ThreadName=Thread-2得到鎖定
★線程Thread-4運行了
★線程Thread-6運行了
ThreadName=Thread-4得到鎖定
ThreadName=Thread-6得到鎖定
★線程Thread-5運行了
ThreadName=Thread-5得到鎖定
★線程Thread-9運行了
★線程Thread-7運行了
★線程Thread-8運行了
ThreadName=Thread-9得到鎖定
ThreadName=Thread-7得到鎖定
ThreadName=Thread-8得到鎖定

  10.方法getHoldCount()、getQueueLength()、getWaitQueueLength()的測試

  示例1:getHoldCount()方法的做用是查詢當前線程保持此鎖定的個數,也就是調用lock()方法的次數。

package test1;

import java.util.concurrent.locks.ReentrantLock;

public class Service {

    private ReentrantLock lock = new ReentrantLock();

    public void serviceMethod1() {
        try {
            lock.lock();
            System.out.println("serviceMethod1 getHoldCount="+ lock.getHoldCount());
            serviceMethod2();
        } finally {
            lock.unlock();
        }
    }

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

}
package test1;

public class Run {

    public static void main(String[] args) {
        Service service = new Service();
        service.serviceMethod1();
    }
}
serviceMethod1 getHoldCount=1
serviceMethod2 getHoldCount=2

  示例2:getQueueLength()方法的做用是返回正等待獲取此鎖定的線程估計數,從輸出能夠看出,有一個線程進入了方法,因爲sleep好久,因此其餘九個線程都在等待獲取此鎖的釋放。

package test2;

import java.util.concurrent.locks.ReentrantLock;

public class Service {

    public ReentrantLock lock = new ReentrantLock();

    public void serviceMethod1() {
        try {
            lock.lock();
            System.out.println("ThreadName=" + Thread.currentThread().getName()+ "進入方法!");
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}
package test2;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.serviceMethod1();
            }
        };

        Thread[] threadArray = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threadArray[i] = new Thread(runnable);
        }
        for (int i = 0; i < 10; i++) {
            threadArray[i].start();
        }
        Thread.sleep(2000);
        System.out.println("有線程數:" + service.lock.getQueueLength() + "在等待獲取鎖!");

    }
}
ThreadName=Thread-1進入方法!
有線程數:9在等待獲取鎖!

  示例3:getWaitQueueLength(newCondition)方法的做用是返回等待於此鎖定相關的給定條件Condition的線程估計數,示例中10個線程都執行了同一個Condition對象的await()方法,則返回值就是10

package test3;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Service {

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

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

    public void notityMethod() {
        try {
            lock.lock();
            System.out.println("有" + lock.getWaitQueueLength(newCondition)
                    + "個線程正在等待newCondition");
            newCondition.signal();
        } finally {
            lock.unlock();
        }
    }

}
package test3;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };

        Thread[] threadArray = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threadArray[i] = new Thread(runnable);
        }
        for (int i = 0; i < 10; i++) {
            threadArray[i].start();
        }
        Thread.sleep(2000);
        service.notityMethod();
    }
}
有10個線程正在等待newCondition

  11.方法hasQueuedThread()、hasQueuedThreads()、hasWaiters()的測試

  示例1:hasQueuedThread(threadA)的做用是查詢指定的線程A是否正在等待獲取此鎖定,hasQueuedThreads()的做用是查詢是否有線程正在等待獲取此鎖定。示例中線程A獲取了此鎖定,所以會打印出這種效果。

package test1;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Service {

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

    public void waitMethod() {
        try {
            lock.lock();
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
package test1;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };

        Thread threadA = new Thread(runnable);
        threadA.start();

        Thread.sleep(500);

        Thread threadB = new Thread(runnable);
        threadB.start();

        Thread.sleep(500);
        System.out.println(service.lock.hasQueuedThread(threadA));
        System.out.println(service.lock.hasQueuedThread(threadB));
        System.out.println(service.lock.hasQueuedThreads());
    }
}
false
true
true

   示例2:hasWaiters(newCondition)方法的做用是查詢是否有線程正在等待與此鎖定有關的condition條件。示例中10個線程都執行了await()方法,且都在等待newCondition條件。

package test2;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Service {

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

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

    public void notityMethod() {
        try {
            lock.lock();
            System.out.println("有沒有線程正在等待newCondition?"
                    + lock.hasWaiters(newCondition) + " 線程數是多少?"
                    + lock.getWaitQueueLength(newCondition));
            newCondition.signal();
        } finally {
            lock.unlock();
        }
    }

}
package test2;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };

        Thread[] threadArray = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threadArray[i] = new Thread(runnable);
        }
        for (int i = 0; i < 10; i++) {
            threadArray[i].start();
        }
        Thread.sleep(2000);
        service.notityMethod();
    }
}
有沒有線程正在等待newCondition?true 線程數是多少?10

  12.方法isFair()、isHeldByCurrentThread()、isLocked()的測試

  示例1:isFair()的做用是判斷是否是公平鎖,在默認的狀況下,ReentrantLock類使用的非公平鎖。

package test1;

import java.util.concurrent.locks.ReentrantLock;

public class Service {

    private ReentrantLock lock;

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

    public void serviceMethod() {
        try {
            lock.lock();
            System.out.println("公平鎖狀況:" + lock.isFair());
        } finally {
            lock.unlock();
        }
    }

}
package test1;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final Service service1 = new Service(true);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service1.serviceMethod();
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();

        final Service service2 = new Service(false);
        runnable = new Runnable() {
            @Override
            public void run() {
                service2.serviceMethod();
            }
        };
        thread = new Thread(runnable);
        thread.start();

    }
}
公平鎖狀況:true
公平鎖狀況:false

  示例2:isHeldByCurrentThread()方法的做用是查詢當前線程是否保持此鎖定,執行完lock.lock();後就保持鎖定,返回true。

package test2;

import java.util.concurrent.locks.ReentrantLock;

public class Service {

    private ReentrantLock lock;

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

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

}
package test2;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final Service service1 = new Service(true);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service1.serviceMethod();
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
    }
}
false
true

  示例3:isLocked()方法的做用是查詢此鎖定是否由任意線程保持,執行lock.lock();後改變返回值。

package test3;

import java.util.concurrent.locks.ReentrantLock;

public class Service {

    private ReentrantLock lock;

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

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

}
package test3;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final Service service1 = new Service(true);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service1.serviceMethod();
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
    }
}
false
true

  13.方法lockInterruptibly()、tryLock()、tryLock(long timeout,TimeUnit unit)的測試

  示例1:調用lock.lock();時,即便線程B被interrupt中斷了,也沒有出現異常,線程A和線程B正常結束。

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    public ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void waitMethod() {
        try {
            lock.lock();
            System.out
                    .println("lock begin " + Thread.currentThread().getName());
            for (int i = 0; i < Integer.MAX_VALUE / 10; i++) {
                Math.random();
            }
            System.out
                    .println("lock   end " + Thread.currentThread().getName());
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}
package test;

import service.MyService;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final MyService service = new MyService();
        Runnable runnableRef = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };

        Thread threadA = new Thread(runnableRef);
        threadA.setName("A");
        threadA.start();
        Thread.sleep(500);
        Thread threadB = new Thread(runnableRef);
        threadB.setName("B");
        threadB.start();
        threadB.interrupt();
        System.out.println("main end!");
    }
}
lock begin A
main end!
lock   end A
lock begin B
lock   end B

  示例2:修改爲lock.lockInterruptibly();線程B被interrupt中斷後,調用調用lockInterruptibly()方法會出現異常。說明了lockInterruptibly()方法的做用是若是當前線程未被中斷,則獲取鎖定,若是已經被中斷則出現異常。

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    public ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void waitMethod() {
        try {
            lock.lockInterruptibly();
            System.out.println("lock " + Thread.currentThread().getName());
            for (int i = 0; i < Integer.MAX_VALUE / 10; i++) {
                Math.random();
            }
        } catch (InterruptedException e) {
            System.out.println("�߳�"+Thread.currentThread().getName()+"����catch~!");
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}
lock A
線程B進入catch~!
java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(Unknown Source)
	at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(Unknown Source)
	at service.MyService.waitMethod(MyService.java:13)
	at test.Run$1.run(Run.java:12)
	at java.lang.Thread.run(Unknown Source)

  示例3:tryLock()方法的做用是,僅在調用時鎖定未被另外一個線程保持的狀況下,才獲取該鎖定。

package service;

import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    public ReentrantLock lock = new ReentrantLock();

    public void waitMethod() {
        if (lock.tryLock()) {
            System.out.println(Thread.currentThread().getName() + "已得到鎖");
        } else {
            System.out.println(Thread.currentThread().getName() + "未得到鎖");
        }
    }
}
package test;

import service.MyService;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final MyService service = new MyService();

        Runnable runnableRef = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };

        Thread threadA = new Thread(runnableRef);
        threadA.setName("A");
        threadA.start();
        Thread threadB = new Thread(runnableRef);
        threadB.setName("B");
        threadB.start();
    }
}
A已得到鎖
B未得到鎖
B已得到鎖
A未得到鎖

  示例4:tryLock(long timeout, TimeUnit.SECONDS)方法的做用是,若是鎖定在給定等待時間內沒有被另外一個線程保持,且當前線程未被中斷,則獲取該鎖定。

package service;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    public ReentrantLock lock = new ReentrantLock();

    public void waitMethod() {
        try {
            if (lock.tryLock(3, TimeUnit.SECONDS)) {
                System.out.println("      " + Thread.currentThread().getName()
                        + "得到鎖的時間:" + System.currentTimeMillis());
                Thread.sleep(10000);
            } else {
                System.out.println("      " + Thread.currentThread().getName()
                        + "沒有得到鎖!");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}
package test;

import service.MyService;

public class Run {

    public static void main(String[] args) throws InterruptedException {
        final MyService service = new MyService();

        Runnable runnableRef = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()
                        + "調用waitMethod" + System.currentTimeMillis());
                service.waitMethod();
            }
        };

        Thread threadA = new Thread(runnableRef);
        threadA.setName("A");
        threadA.start();
        Thread threadB = new Thread(runnableRef);
        threadB.setName("B");
        threadB.start();
    }
}
B調用waitMethod的時間:1525681079395
A調用waitMethod的時間:1525681079395
      B得到鎖的時間:1525681079396
      A沒有得到鎖!

  14.方法awaitUninterruptibly()的使用

  示例1:使用condition.await();正常狀況下,線程在啓動3000毫秒後,被interrupt中斷後會發生異常。

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Service {

    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void testMethod() {
        try {
            lock.lock();
            System.out.println("wait begin");
            condition.await();
            System.out.println("wait   end");
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("catch");
        } finally {
            lock.unlock();
        }

    }
}
package extthread;

import service.Service;

public class MyThread extends Thread {

    private Service service;

    public MyThread(Service service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.testMethod();
    }

}
package test;

import service.Service;
import extthread.MyThread;

public class Run {

    public static void main(String[] args) {
        try {
            Service service = new Service();
            MyThread myThread = new MyThread(service);
            myThread.start();
            Thread.sleep(3000);
            myThread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
wait begin
java.lang.InterruptedException
catch
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(Unknown Source)
	at service.Service.testMethod(Service.java:15)
	at extthread.MyThread.run(MyThread.java:16)

  示例2:修改爲awaitUninterruptibly();而後刪除catch部分,即便線程中斷,程序也不會出現異常。

package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Service {

    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void testMethod() {
        try {
            lock.lock();
            System.out.println("wait begin");
            condition.awaitUninterruptibly();
            System.out.println("wait   end");
        } finally {
            lock.unlock();
        }

    }
}
wait begin

  15.方法awaitUntil()的使用

  示例:condition.awaitUntil(calendarRef.getTime());方法能夠在指定等待時間後自動喚醒本身。

package service;

import java.util.Calendar;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Service {

    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void waitMethod() {
        try {
            Calendar calendarRef = Calendar.getInstance();
            calendarRef.add(Calendar.SECOND, 10);
            lock.lock();
            System.out.println("wait begin timer=" + System.currentTimeMillis());
            condition.awaitUntil(calendarRef.getTime());
            System.out.println("wait   end timer=" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public void notifyMethod() {
        try {
            Calendar calendarRef = Calendar.getInstance();
            calendarRef.add(Calendar.SECOND, 10);
            lock.lock();
            System.out.println("notify begin timer=" + System.currentTimeMillis());
            condition.signalAll();
            System.out.println("notify   end timer=" + System.currentTimeMillis());
        } finally {
            lock.unlock();
        }

    }
}
package extthread;

import service.Service;

public class MyThreadA extends Thread {

    private Service service;

    public MyThreadA(Service service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.waitMethod();
    }

}
package extthread;

import service.Service;

public class MyThreadB extends Thread {

    private Service service;

    public MyThreadB(Service service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.notifyMethod();
    }

}

  Run1:在等待了10秒後自動喚醒本身。

package test;

import service.Service;
import extthread.MyThreadA;
import extthread.MyThreadB;

public class Run1 {

    public static void main(String[] args) throws InterruptedException {
        Service service = new Service();
        MyThreadA myThreadA = new MyThreadA(service);
        myThreadA.start();
    }

}
wait begin timer=1525681887037
wait   end timer=1525681897020

   Run2:在等待時間到達前,能夠被其餘線程提早喚醒。

package test;

import service.Service;
import extthread.MyThreadA;
import extthread.MyThreadB;

public class Run2 {

    public static void main(String[] args) throws InterruptedException {
        Service service = new Service();
        MyThreadA myThreadA = new MyThreadA(service);
        myThreadA.start();

        Thread.sleep(2000);

        MyThreadB myThreadB = new MyThreadB(service);
        myThreadB.start();
    }

}
wait begin timer=1525681991401
notify begin timer=1525681993380
notify   end timer=1525681993380
wait   end timer=1525681993380

  16.使用Condition實現順序執行

  示例:使用Condition對象能夠對線程執行的業務進行排序規劃。使用3個Condition對象,同時經過設置nextPrintWho變量以及判斷語句來實現按順序打印。

package finaltools;

public class F {
    volatile public static int nextPrintWho = 1;
}
package test.run;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Run {

    volatile private static int nextPrintWho = 1;
    private static ReentrantLock lock = new ReentrantLock();
    final private static Condition conditionA = lock.newCondition();
    final private static Condition conditionB = lock.newCondition();
    final private static Condition conditionC = lock.newCondition();

    public static void main(String[] args) {

        Thread threadA = new Thread() {
            public void run() {
                try {
                    lock.lock();
                    while (nextPrintWho != 1) {
                        conditionA.await();
                    }
                    for (int i = 0; i < 3; i++) {
                        System.out.println("ThreadA " + (i + 1));
                    }
                    nextPrintWho = 2;
                    conditionB.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };

        Thread threadB = new Thread() {
            public void run() {
                try {
                    lock.lock();
                    while (nextPrintWho != 2) {
                        conditionB.await();
                    }
                    for (int i = 0; i < 3; i++) {
                        System.out.println("ThreadB " + (i + 1));
                    }
                    nextPrintWho = 3;
                    conditionC.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };

        Thread threadC = new Thread() {
            public void run() {
                try {
                    lock.lock();
                    while (nextPrintWho != 3) {
                        conditionC.await();
                    }
                    for (int i = 0; i < 3; i++) {
                        System.out.println("ThreadC " + (i + 1));
                    }
                    nextPrintWho = 1;
                    conditionA.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };
        Thread[] aArray = new Thread[5];
        Thread[] bArray = new Thread[5];
        Thread[] cArray = new Thread[5];

        for (int i = 0; i < 5; i++) {
            aArray[i] = new Thread(threadA);
            bArray[i] = new Thread(threadB);
            cArray[i] = new Thread(threadC);

            aArray[i].start();
            bArray[i].start();
            cArray[i].start();
        }

    }
}
ThreadA 1
ThreadA 2
ThreadA 3
ThreadB 1
ThreadB 2
ThreadB 3
ThreadC 1
ThreadC 2
ThreadC 3
ThreadA 1
ThreadA 2
ThreadA 3
ThreadB 1
ThreadB 2
ThreadB 3
ThreadC 1
ThreadC 2
ThreadC 3
ThreadA 1
ThreadA 2
ThreadA 3
ThreadB 1
ThreadB 2
ThreadB 3
ThreadC 1
ThreadC 2
ThreadC 3
ThreadA 1
ThreadA 2
ThreadA 3
ThreadB 1
ThreadB 2
ThreadB 3
ThreadC 1
ThreadC 2
ThreadC 3
ThreadA 1
ThreadA 2
ThreadA 3
ThreadB 1
ThreadB 2
ThreadB 3
ThreadC 1
ThreadC 2
ThreadC 3

  2、使用ReentrantReadWriteLock類

  類ReentrantLock具備徹底互斥排他的效果,即同一時間只有一個線程在執行ReentrantLock.lock()方法後面的任務。這樣作雖然保證了實例變量的線程安全性,但效率確實很是低下的。因此可使用ReentrantReadWriteLock類來加快運行效率,在某些不須要操做實例變量的方法中,徹底可使用讀寫鎖ReentrantReadWriteLock來提高該方法的代碼運行速度。

  讀寫鎖表示也有兩個鎖,一個是讀操做相關的鎖,也成爲共享鎖;另外一個是寫操做相關的鎖,也叫排他鎖。也就是多個 讀鎖之間不互斥,讀鎖與寫鎖互斥,寫鎖與寫鎖互斥。在沒有線程進入寫操做時,進行讀取操做的多個線程均可以獲取該鎖,而進行寫入操做的線程只有在獲取寫鎖後才能進行寫入操做。即多個線程能夠同時進行讀取操做,可是同一時刻只容許一個線程進行寫入操做。

  1.類ReentrantReadWriteLock的使用:讀讀共享

  示例:從輸出結果能夠看出,兩個線程幾乎同時進入lock()方法後面的代碼。說明在此使用讀鎖lock.readLock().lock();能夠提升程序運行效率,容許多個線程同時執行lock()後面的代碼。

package service;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Service {

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public void read() {
        try {
            try {
                lock.readLock().lock();
                System.out.println("得到讀鎖" + Thread.currentThread().getName()
                        + " " + System.currentTimeMillis());
                Thread.sleep(10000);
            } finally {
                lock.readLock().unlock();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
package extthread;

import service.Service;

public class ThreadA extends Thread {

    private Service service;

    public ThreadA(Service service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.read();
    }
}
package extthread;

import service.Service;

public class ThreadB extends Thread {

    private Service service;

    public ThreadB(Service service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.read();
    }
}
package test;

import service.Service;
import extthread.ThreadA;
import extthread.ThreadB;

public class Run {

    public static void main(String[] args) {

        Service service = new Service();

        ThreadA a = new ThreadA(service);
        a.setName("A");

        ThreadB b = new ThreadB(service);
        b.setName("B");

        a.start();
        b.start();

    }

}
得到讀鎖B 1525682951639
得到讀鎖A 1525682951639

  2.類ReentrantReadWriteLock的使用:寫寫互斥

  示例:修改上例中的Service類,改爲lock.writeLock().lock();從輸出結果能夠看出,同一時間只容許一個線程執行lock()後面的代碼,兩個線程執行lock()後面的代碼的間隔是10000毫秒,即第一個線程執行完畢釋放鎖後第二個線程才能夠執行。

package service;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Service {

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public void write() {
        try {
            try {
                lock.writeLock().lock();
                System.out.println("得到寫鎖" + Thread.currentThread().getName()
                        + " " + System.currentTimeMillis());
                Thread.sleep(10000);
            } finally {
                lock.writeLock().unlock();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
得到寫鎖A 1525683149041
得到寫鎖B 1525683159041

  3.類ReentrantReadWriteLock的使用:讀寫互斥

  示例:修改Service類,定義讀方法和寫方法,線程A讀,線程B寫,線程A執行1000毫秒後線程B執行,從輸出結果能夠看出,「讀寫」操做確實是互斥的。

package service;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Service {

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public void read() {
        try {
            try {
                lock.readLock().lock();
                System.out.println("得到讀鎖" + Thread.currentThread().getName()
                        + " " + System.currentTimeMillis());
                Thread.sleep(10000);
            } finally {
                lock.readLock().unlock();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void write() {
        try {
            try {
                lock.writeLock().lock();
                System.out.println("得到寫鎖" + Thread.currentThread().getName()
                        + " " + System.currentTimeMillis());
                Thread.sleep(10000);
            } finally {
                lock.writeLock().unlock();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
得到讀鎖A 1525683361081
得到寫鎖B 1525683371082

  4.類ReentrantReadWriteLock的使用:寫讀互斥

  示例:修改上例,使線程A寫,線程B讀,線程A執行1000毫秒後線程B執行,從輸出結果能夠看出,「寫讀」操做也是互斥的。

得到寫鎖A 1525683538622
得到讀鎖B 1525683548623
相關文章
相關標籤/搜索