除了使用關鍵字 synchronized 支持的隱式鎖(對象的內置鎖)外,Concurrency API 支持由 Lock 接口指定的各類顯示鎖。顯示鎖能控制更細的粒度,所以也有更好的性能,在邏輯上也比較清晰。安全
標準 JDK中提供了多種顯示鎖的實現,將在下面的章節中進行介紹異步
直接上代碼ide
例子1:性能
public class SyncSameObjectTest1 implements Runnable{this
public void lord1(){.net
try {線程
Thread.sleep(2000);對象
System.out.println("線程:"+Thread.currentThread().getName()+"運行時間:"+System.currentTimeMillis());接口
} catch (Exception e) {get
}
}
//聲明顯示鎖
private Lock lock =new ReentrantLock();
/* 這裏將Lock做爲線程變量,使得每次建立線程都建立一個Lock對象(對象鎖若是不是同一個對象就能異步執行,互不影響)。
* 注意使用Lock鎖的時候,必定要包裹在try catch finally裏,使得出現運行期異常的時候,鎖可以釋放!*/
public void run(){
try {
lock.lock();//開始鎖定
lord1();
} catch (Exception e) {
}finally{
lock.unlock();//釋放鎖
}
}
public static void main (String args[]){
try {
ExecutorService eService = Executors.newCachedThreadPool();
System.out.println("任務開始lock顯示鎖");
for (int i = 0; i < 3; i++) {
eService.submit(new SyncSameObjectTest1());
}
TimeUnit.SECONDS.sleep(10);
System.out.println("任務執行結束");
eService.shutdown();
} catch (Exception e) {
}
}
}
這裏採用線程池去啓動線程,每次啓動線程都是新的線程,從結果能夠看到,Lock鎖三個線程是異步執行的,相互不影響。形成這種緣由是由於對象是不同的。
改造下試試:
例子2:
public class SyncSameObjectTest1 implements Runnable{
private Lock lock;
public void lord1(){
try {
Thread.sleep(2000);
System.out.println("線程:"+Thread.currentThread().getName()+"運行時間:"+System.currentTimeMillis());
} catch (Exception e) {
}
}
public SyncSameObjectTest1(Lock lock){
this.lock=lock;
}
public SyncSameObjectTest1(){
}
public void run(){
try {
lock.lock();//開始鎖定
lord1();
} catch (Exception e) {
lock.unlock();//釋放鎖
}finally{
lock.unlock();
}
}
public static void main (String args[]){
Lock lock =new ReentrantLock();
try {
ExecutorService eService = Executors.newCachedThreadPool();
System.out.println("任務開始lock顯示鎖");
for (int i = 0; i < 3; i++) {
eService.submit(new SyncSameObjectTest1(lock));
}
TimeUnit.SECONDS.sleep(10);
System.out.println("任務執行結束");
eService.shutdown();
} catch (Exception e) {
}
}
}
這裏在main裏面實例化一個鎖(或者同一對象調用),線程實例化的時候,將該鎖(同一個對象)傳進去,已是同步運行了。說明了Lock顯式鎖是對象鎖。看運行順序及時間可知
任務開始lock顯示鎖
線程:pool-1-thread-1運行時間:1514537154767
線程:pool-1-thread-2運行時間:1514537156767
線程:pool-1-thread-3運行時間:1514537158767
任務執行結束
當第一個任務獲取鎖時,第二個任務獲取鎖的狀態信息:
例子3:
lock顯示鎖 鎖用一個對象調用與synchronized隱式鎖同一對象結果一致
public class SynchronizedTest {
public static void main(String[] args) {
//線程數
int threadNum = 5;
final Syn syn = new Syn();
Thread[] threads = new Thread[threadNum];
//記錄運行時間
long l = System.currentTimeMillis();
for (int i = 0; i < threadNum; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 100000; j++) {
syn.increase();
}
}
});
threads[i].start();
}
//等待全部線程結束
try {
for (int i = 0; i < threadNum; i++)
threads[i].join();
//main線程要等到threads[5]線程運行結束後,纔會往下執行輸出。若是不加threads[i].join(),
//main線程和threads[i]線程是並行的。而加上threads[i].join(),程序就變成是順序執行了。
//咱們在用到join()的時候,一般都是main線程等到其餘多個線程執行完畢後再繼續執行。其餘多個線程之間並不須要互相等待。
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(syn + " : " + (System.currentTimeMillis() - l) + "ms");
}
}
class Syn {
private int count = 0;
private Lock lock = new ReentrantLock();
//利用synchronized
public void increase() {
synchronized (this) {
count++;
}
}
//利用ReentrantLock類同步
public void increaseLock() {
lock.lock();
count++;
lock.unlock();
}
//volatile 不是線程安全的 不保證原子性
public void increaseVolatile() {
count = count + 1;
}
@Override public String toString() { return String.valueOf(count); } } 結果:500000 : 20ms