1、synchronized
同步鎖的用法。它可以在代碼中使用,也可以用來修飾函數。它的特性是:同一時間內,只有一個擁有鎖的線程才能運行。
synchronized (obj) { while (<condition does not hold>) obj.wait(); ... // Perform action appropriate to condition }
常用方法:
obj為鎖對象。
obj.wait() :調用后,該線程會釋放同步鎖obj對象,並使進程處於等待狀態。
obj.notify():調用后將喚醒等待obj鎖對象的線程隊列中的第一個線程。喚醒等待該鎖的線程隊列中的第一個線程,並且當前進程釋未釋放鎖,得在當前線程中需調用wait釋放鎖,使當前進程等待,喚醒的線程才可以執行,否則就等待線程釋放它等待的鎖。
obj.notifyAll() :調用后喚醒等待obj對象的線程隊列中的所有線程,誰得到了線程釋放的鎖誰就運行。
NOTE:notify 和notifyAll只是激活了線程,但線程還是得等到鎖對象才能運行。若不激活wait()后線程阻塞了,它不會主動去獲取鎖,因此當沒有線程占用鎖時,若沒激活線程仍然不會運行。
例如下面的例子,大於105的時候賣票,低於100的時候制票:
public class LockDemo { private static int ticketNumber = 103; private static final Object ticketLock = new Object(); public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new SellTicket()); t1.start(); Thread t2 = new Thread(new MakeTicket()); t2.start(); // synchronized (ticketLock) { // while(true) // { // ticketLock.wait(); // System.out.println("dddddddddddddddddddddd"); // } // // } } static class SellTicket implements Runnable{ public void run() { synchronized (ticketLock) { while(true){ if(ticketNumber <= 100) { //少於100張票后就停止售票,制造票,這里wait()會是釋放ticketLock鎖對象,讓制票線程啟動 System.out.println("賣完票"); ticketLock.notify(); try { ticketLock.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { try { Thread.sleep(1000); } catch(Exception e) { } System.out.println("賣票"+ ticketNumber); ticketNumber--; } } } } } static class MakeTicket implements Runnable{ public void run() { synchronized (ticketLock) { while(true) { if(ticketNumber>=105) { System.out.println("制造好票"); ticketLock.notify(); try { ticketLock.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { try { Thread.sleep(1000); } catch(Exception e) { } System.out.println("制造票" + ticketNumber); ticketNumber++; } } } } } }
2、異步鎖 Lock。
jdk1.5提供了多線程的升級解決方法(顯示的鎖機制) 將同步synchronized替換成了顯示的Lock操作
----》lock() unlock() 將Object中的wait、notify/notifyAll 替換成了 Condition (await/signal/signalAll)
該對象可以 Lock.newCondition() 獲取 一個鎖可以綁定多個condition對象,避免了因同步嵌套導致死鎖問題的發生,激活指定的線程。
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockDemo2 { private static int ticketNumber = 103; private static final Object ticketLock = new Object(); private static Lock lock = new ReentrantLock(); private static Condition condition_sell = lock.newCondition(); private static Condition condition_make = lock.newCondition(); public static void main(String[] args) { // TODO Auto-generated method stub Thread t1 = new Thread(new SellTicket()); t1.start(); Thread t2 = new Thread(new MakeTicket()); t2.start(); } static class SellTicket implements Runnable{ public void run() { // TODO Auto-generated method stub lock.lock(); try{ while(true){ if(ticketNumber <= 100) { //少於100張票后就停止售票,制造票,這里wait()會是釋放ticketLock鎖對象,讓制票線程啟動 condition_make.signal();//激活制票的線程 condition_sell.await(); } else { Thread.sleep(1000); System.out.println("賣票"+ ticketNumber); ticketNumber--; } } } catch(Exception e){} finally { lock.unlock(); } } } static class MakeTicket implements Runnable{ public void run() { // TODO Auto-generated method stub lock.lock(); try{ while(true) { if(ticketNumber>=105) { condition_sell.signal();//激活賣票的線程 condition_make.await(); } else { Thread.sleep(1000); System.out.println("制造票" + ticketNumber); ticketNumber++; } } }catch(Exception e){} finally { lock.unlock(); } } } }
