Lock是java.util.concurrent.locks包下的接口,Lock 實現提供了比使用synchronized 方法和語句可得到的更普遍的鎖定操做,它能以更優雅的方式處理線程同步問題,固然也能實現sychronized同樣的效果,代碼以下:java
package org.thread; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Output { private Lock lock = new ReentrantLock(); public void output(String name) { try { lock.lock(); for (int i = 0; i < name.length(); i++) { System.out.print(name.charAt(i)); } } catch (Exception e) { } finally { lock.unlock(); } } }
如今看看併發
package org.thread; public class Outputer { public synchronized void input(String name){ for(int i =0;i<name.length();i++){ System.out.print(name.charAt(i)); } } }
這兩個方法其實都是爲了實現數據同步dom
package org.thread; public class LockTest { public static void main(String[] args) { final Outputer outputer = new Outputer(); final Output output = new Output(); Runnable runnable1 = new Runnable() { public void run() { outputer.input("Heinrich"); } }; Runnable runnable2 = new Runnable() { @Override public void run() { outputer.input("AmiLoveMe"); } }; Runnable runnable3 = new Runnable() { public void run() { output.output("Heinrich"); } }; Runnable runnable4 = new Runnable() { @Override public void run() { output.output("AmiLoveMe"); } }; new Thread(runnable2).start(); new Thread(runnable1).start(); new Thread(runnable3).start(); new Thread(runnable4).start(); } }
看看控制檯的信息是否是咱們想要的,結果確定是的,反正我以爲是ide
AmiLoveMeHeinrichHeinrichAmiLoveMe 是我要的結果,有序,數據一致
這樣就實現了和sychronized同樣的同步效果,須要注意的是,用sychronized修飾的方法或者語句塊在代碼執行完以後鎖自動釋放,而是用Lock須要咱們手動釋放鎖,因此爲了保證鎖最終被釋放(發生異常狀況),要把互斥區放在try內,釋放鎖放在finally內。性能
若是說這就是Lock,那麼它不能成爲同步問題更完美的處理方式,下面要介紹的是讀寫鎖(ReadWriteLock),咱們會有一種需求,在對數據進行讀寫的時候,爲了保證數據的一致性和完整性,須要讀和寫是互斥的,寫和寫是互斥的,可是讀和讀是不須要互斥的,這樣讀和讀不互斥性能更高些,來看一下不考慮互斥狀況的代碼原型:this
如今看代碼:沒有讀寫鎖的spa
package org.thread; public class Data { private Integer data; public void get() { System.out.println(Thread.currentThread().getName()+"準備讀取數據"); try { Thread.sleep(4000); } catch (Exception e) { } System.out.println(Thread.currentThread().getName()+"讀取"+this.data); } public void set(Integer data) { System.out.println(Thread.currentThread().getName()+"準備寫入數據"); try { Thread.sleep(4000); } catch (Exception e) { } this.data = data; System.out.println(Thread.currentThread().getName()+"寫入"+this.data); } }
package org.thread; import java.util.Random; public class DataThread { public static void main(String[] args) { final Data data = new Data(); for (int i = 0; i < 10; i++) { Runnable runnable1 = new Runnable() { @Override public void run() { data.set(new Random().nextInt(100)); } }; new Thread(runnable1).start(); } for (int i = 0; i < 10; i++) { Runnable runnable2 = new Runnable() { @Override public void run() { data.get(); } }; new Thread(runnable2).start(); } } }
看看控制檯線程
Thread-0準備寫入數據 Thread-8準備寫入數據 Thread-5準備寫入數據 Thread-4準備寫入數據 Thread-3準備寫入數據 Thread-2準備寫入數據 Thread-7準備寫入數據 Thread-1準備寫入數據 Thread-6準備寫入數據 Thread-9準備寫入數據 Thread-10準備讀取數據 Thread-12準備讀取數據 Thread-11準備讀取數據 Thread-14準備讀取數據 Thread-15準備讀取數據 Thread-16準備讀取數據 Thread-13準備讀取數據 Thread-17準備讀取數據 Thread-18準備讀取數據 Thread-19準備讀取數據 Thread-7寫入28 Thread-3寫入56 Thread-8寫入83 Thread-2寫入88 Thread-9寫入83 Thread-5寫入88 Thread-0寫入84 Thread-6寫入28 Thread-1寫入28 Thread-4寫入28 Thread-19讀取56 Thread-12讀取56 Thread-14讀取56 Thread-13讀取56 Thread-16讀取56 Thread-10讀取56 Thread-11讀取56 Thread-15讀取56 Thread-17讀取56 Thread-18讀取56
咱們要實現寫入和寫入互斥,讀取和寫入互斥,讀取和讀取互斥,在set和get方法加入code
synchronized修飾符接口
package org.thread; public class Data { private Integer data; public synchronized void get() { System.out.println(Thread.currentThread().getName()+"準備讀取數據"); try { Thread.sleep(4000); } catch (Exception e) { } System.out.println(Thread.currentThread().getName()+"讀取"+this.data); } public synchronized void set(Integer data) { System.out.println(Thread.currentThread().getName()+"準備寫入數據"); try { Thread.sleep(4000); } catch (Exception e) { } this.data = data; System.out.println(Thread.currentThread().getName()+"寫入"+this.data); } }
Thread-0準備寫入數據 Thread-0寫入54 Thread-19準備讀取數據 Thread-19讀取54 Thread-18準備讀取數據 Thread-18讀取54 Thread-17準備讀取數據 Thread-17讀取54 Thread-16準備讀取數據 Thread-16讀取54 Thread-15準備讀取數據 Thread-15讀取54 Thread-14準備讀取數據 Thread-14讀取54 Thread-13準備讀取數據 Thread-13讀取54 Thread-12準備讀取數據 Thread-12讀取54 Thread-11準備讀取數據 Thread-11讀取54 Thread-10準備讀取數據 Thread-10讀取54 Thread-9準備寫入數據 Thread-9寫入42 Thread-8準備寫入數據 Thread-8寫入86 Thread-1準備寫入數據 Thread-1寫入30 Thread-2準備寫入數據 Thread-2寫入3 Thread-4準備寫入數據 Thread-4寫入81 Thread-3準備寫入數據 Thread-3寫入72 Thread-5準備寫入數據 Thread-5寫入15 Thread-6準備寫入數據 Thread-6寫入16 Thread-7準備寫入數據 Thread-7寫入33
咱們發現,雖然寫入和寫入互斥了,讀取和寫入也互斥了,可是讀取和讀取之間也互斥了,不能併發執行,效率較低,用讀寫鎖實現代碼以下:
package org.thread; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class DataSyn { private Integer data; private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public void get() { System.out.println(Thread.currentThread().getName() + "準備讀取數據"); readWriteLock.readLock().lock();; try { Thread.sleep(2000); System.out.println(Thread.currentThread().getName() + "正在讀取數據" + this.data); } catch (Exception e) { } finally { readWriteLock.readLock().unlock(); } } public void set(Integer data) { System.out.println(Thread.currentThread().getName() + "準備寫入數據"); readWriteLock.writeLock().lock();; try { this.data = data; System.out.println(Thread.currentThread().getName()+"正在寫入"+data); } catch (Exception e) { e.printStackTrace(); }finally{ readWriteLock.writeLock().unlock(); } } }
Thread-5準備寫入數據 Thread-5正在寫入85 Thread-1準備寫入數據 Thread-1正在寫入74 Thread-6準備寫入數據 Thread-6正在寫入28 Thread-0準備寫入數據 Thread-0正在寫入93 Thread-3準備寫入數據 Thread-4準備寫入數據 Thread-7準備寫入數據 Thread-8準備寫入數據 Thread-3正在寫入75 Thread-2準備寫入數據 Thread-2正在寫入75 Thread-4正在寫入70 Thread-7正在寫入65 Thread-9準備寫入數據 Thread-8正在寫入92 Thread-9正在寫入88
這個是否是效率更好了,固然咯,要否則說這麼多幹什麼