Java 同步线程的方法有三种,分别是使用java.util.concurrent 框架,synchronized 关键字,volatile 关键字,直接使用java.util.concurrent 框架并不常用,但是我们在理解java.util.concurrent 框架的锁与条件锁后,对理想synchronized 就更加方便。
java.util.concurrent 框架是一个线程同步框架,它包含Lock, ReentrantLock, Condition 等出来线程的工具类,通过该工具列可以实现线程的同步与条件同步,我们写一个买票的例子来说明这些类的使用。
假设我们要买火车票回家,我们为火车站写一个买票代码,我们为车站提供了一个出票方法与查看剩余票数的方法,代码如下:
public class Dome03 { /** 火车票*/ private int ticketNumble ; public Dome03(int inifTicketNumble) { ticketNumble = inifTicketNumble; } /** 查看车票数量 * @return */ public int queryTicketNumble() { return ticketNumble; } /** * 出票 */ public void goTicket() { if(ticketNumble > 0) { threadSleep(1000);// 出票延迟 <- --ticketNumble; System.out.println(Thread.currentThread().getName() + "窗口出票了,当前剩余票数是:" + queryTicketNumble() ); } } /** * 延迟 */ private void threadSleep(long time) { try { Thread.sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } } }我们来编写一个两个窗口买票的场景实例,假设有两个窗口买票,每个窗口都排队买票100人,两个窗口并发的进行买票。代码如下:
/** * 出现了负数 */ public void sceneOne() { // 买票窗口01 Thread ticketWindow01 = new Thread(new Runnable() { @Override public void run() { for(int lineUpPeople = 100; lineUpPeople >0; lineUpPeople--) goTicket(); } }, "ticketWindow01"); // 买票窗口02 Thread ticketWindow02 = new Thread(new Runnable() { @Override public void run() { for(int lineUpPeople = 100; lineUpPeople >0; lineUpPeople--) goTicket(); } }, "ticketWindow02"); ticketWindow01.start(); ticketWindow02.start(); } public static void main(String[] args) { int ticketNumble = 100; new Dome03(ticketNumble).sceneOne(); }运行有如下结果: 正常情况: ticketWindow01窗口出票了,当前剩余票数是:3 ticketWindow02窗口出票了,当前剩余票数是:2 异常情况: ticketWindow02窗口出票了,当前剩余票数是:1 ticketWindow01窗口出票了,当前剩余票数是:1
运行有如下结果: ticketWindow01窗口出票了,当前剩余票数是:9 ticketWindow02窗口出票了,当前剩余票数是:8 ticketWindow01窗口出票了,当前剩余票数是:7 ticketWindow02窗口出票了,当前剩余票数是:6 ticketWindow01窗口出票了,当前剩余票数是:5 ticketWindow02窗口出票了,当前剩余票数是:4 ticketWindow01窗口出票了,当前剩余票数是:3 ticketWindow02窗口出票了,当前剩余票数是:2 ticketWindow01窗口出票了,当前剩余票数是:1 ticketWindow02窗口出票了,当前剩余票数是:0
void lock() 获得对象锁,如果锁同时被另一个线程拥有,该线程被阻塞。 void unlock() 释放锁 ReentranLock() 可重入锁 ReentranLock(boolean fair) 公平锁,阻塞时间越长,优先执行,注意:性能慢