Lock是Java.util.concurrent.locks包下的接口,Lock 實現提供了比使用synchronized 方法和語句可獲得的更廣泛的鎖定操作,它能以更優雅的方式處理線程同步問題,我們拿Java線程(二)中的一個例子簡單的實現一下和sychronized一樣的效果,代碼如下:
- public class LockTest {
- public static void main(String[] args) {
- final Outputter1 output = new Outputter1();
- new Thread() {
- public void run() {
- output.output("zhangsan");
- };
- }.start();
- new Thread() {
- public void run() {
- output.output("lisi");
- };
- }.start();
- }
- }
- class Outputter1 {
- private Lock lock = new ReentrantLock();// 鎖對象
- public void output(String name) {
- // TODO 線程輸出方法
- lock.lock();// 得到鎖
- try {
- for(int i = 0; i < name.length(); i++) {
- System.out.print(name.charAt(i));
- }
- } finally {
- lock.unlock();// 釋放鎖
- }
- }
- }
如果說這就是Lock,那麼它不能成爲同步問題更完美的處理方式,下面要介紹的是讀寫鎖(ReadWriteLock),我們會有一種需求,在對數據進行讀寫的時候,爲了保證數據的一致性和完整性,需要讀和寫是互斥的,寫和寫是互斥的,但是讀和讀是不需要互斥的,這樣讀和讀不互斥性能更高些,來看一下不考慮互斥情況的代碼原型:
- public class ReadWriteLockTest {
- public static void main(String[] args) {
- final Data data = new Data();
- for (int i = 0; i < 3; i++) {
- new Thread(new Runnable() {
- public void run() {
- for (int j = 0; j < 5; j++) {
- data.set(new Random().nextInt(30));
- }
- }
- }).start();
- }
- for (int i = 0; i < 3; i++) {
- new Thread(new Runnable() {
- public void run() {
- for (int j = 0; j < 5; j++) {
- data.get();
- }
- }
- }).start();
- }
- }
- }
- class Data {
- private int data;// 共享數據
- public void set(int data) {
- System.out.println(Thread.currentThread().getName() + "準備寫入數據");
- try {
- Thread.sleep(20);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- this.data = data;
- System.out.println(Thread.currentThread().getName() + "寫入" + this.data);
- }
- public void get() {
- System.out.println(Thread.currentThread().getName() + "準備讀取數據");
- try {
- Thread.sleep(20);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(Thread.currentThread().getName() + "讀取" + this.data);
- }
- }
- Thread-1準備寫入數據
- Thread-3準備讀取數據
- Thread-2準備寫入數據
- Thread-0準備寫入數據
- Thread-4準備讀取數據
- Thread-5準備讀取數據
- Thread-2寫入12
- Thread-4讀取12
- Thread-5讀取5
- Thread-1寫入12
- public synchronized void set(int data) {...}
- public synchronized void get() {...}
- Thread-0準備寫入數據
- Thread-0寫入9
- Thread-5準備讀取數據
- Thread-5讀取9
- Thread-5準備讀取數據
- Thread-5讀取9
- Thread-5準備讀取數據
- Thread-5讀取9
- Thread-5準備讀取數據
- Thread-5讀取9
- class Data {
- private int data;// 共享數據
- private ReadWriteLock rwl = new ReentrantReadWriteLock();
- public void set(int data) {
- rwl.writeLock().lock();// 取到寫鎖
- try {
- System.out.println(Thread.currentThread().getName() + "準備寫入數據");
- try {
- Thread.sleep(20);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- this.data = data;
- System.out.println(Thread.currentThread().getName() + "寫入" + this.data);
- } finally {
- rwl.writeLock().unlock();// 釋放寫鎖
- }
- }
- public void get() {
- rwl.readLock().lock();// 取到讀鎖
- try {
- System.out.println(Thread.currentThread().getName() + "準備讀取數據");
- try {
- Thread.sleep(20);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(Thread.currentThread().getName() + "讀取" + this.data);
- } finally {
- rwl.readLock().unlock();// 釋放讀鎖
- }
- }
- }
部分輸出結果:
- Thread-4準備讀取數據
- Thread-3準備讀取數據
- Thread-5準備讀取數據
- Thread-5讀取18
- Thread-4讀取18
- Thread-3讀取18
- Thread-2準備寫入數據
- Thread-2寫入6
- Thread-2準備寫入數據
- Thread-2寫入10
- Thread-1準備寫入數據
- Thread-1寫入22
- Thread-5準備讀取數據
從結果可以看出實現了我們的需求,這只是鎖的基本用法,鎖的機制還需要繼續深入學習。