Java 的2种锁用法
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(); } } } }