Java:多线程之生产者与消费者
要求:用两个线程模拟存票、售票过程。但要求每存入一张票,就售出一张票,售出后,再存入,直到售完为止。
用到的知识点:线程等待、唤醒、可能的线程中断异常
下面的方式一和方式二采用的是唤醒所有等待的线程,即wait()和notify()方法
方式一:继承Thread
class Tickets //定义(资源)票类 { protected int size;//总票数 int number=0; //票号 Boolean available=false;//表示当前是否有票可售 public Tickets(int size) { this.size = size; } public synchronized void store() //同步方法,实现存票功能 { if(available) //如果线程还有票可售,则存票线程等待 try{wait();} catch(InterruptedException e){} System.out.println(Thread.currentThread().getName()+"存入第【"+(++number)+"】张票"); available = true; notify(); //存票后,唤醒售票线程开始售票 } public synchronized void sale() //同步方法,实现售票功能 { if(!available) //如果线程没有票可售,则售票线程等待 try{wait();} catch(InterruptedException e){} System.out.println(Thread.currentThread().getName()+"售出第【"+(number)+"】张票"); available = false; notify(); //售票后,唤醒存票线程开始存票 } } class Productor extends Thread //定义生产者(存票)线程类 { private Tickets t; public Productor(Tickets t) { this.t = t; } public void run() { while(true) { if(t.number<t.size) t.store(); else System.exit(0); } } } class Costomer extends Thread //定义消费者(售票)线程类 { private Tickets t; public Costomer(Tickets t) { this.t = t; } public void run() { while(true) { if(t.number<=t.size) t.sale(); else System.exit(0); } } } class TicketStoreSale3 { public static void main(String[] args) { Tickets t = new Tickets(10); Productor t1 = new Productor(t); Costomer t2 = new Costomer(t); t1.start(); t2.start(); } }
方式二:实现Runnable接口
class Tickets //定义(资源)票类 { protected int size;//总票数 int number=0; //票号 Boolean available=false;//表示当前是否有票可售 public Tickets(int size) { this.size = size; } public synchronized void store() //同步方法,实现存票功能 { if(available) //如果线程还有票可售,则存票线程等待 try{wait();} catch(InterruptedException e){} System.out.println(Thread.currentThread().getName()+"存入第【"+(++number)+"】张票"); available = true; notify(); //存票后,唤醒售票线程开始售票 } public synchronized void sale() //同步方法,实现售票功能 { if(!available) //如果线程没有票可售,则售票线程等待 try{wait();} catch(InterruptedException e){} System.out.println(Thread.currentThread().getName()+"售出第【"+(number)+"】张票"); available = false; notify(); //售票后,唤醒存票线程开始存票 } } class Productor implements Runnable //实现一个接口,生产者(存票)线程类 { private Tickets t; public Productor(Tickets t) { this.t = t; } public void run() { while(true) { if(t.number<t.size) t.store(); else System.exit(0); } } } class Costomer implements Runnable //实现一个接口,消费者(售票)线程类 { private Tickets t; public Costomer(Tickets t) { this.t = t; } public void run() { while(true) { if(t.number<=t.size) t.sale(); else System.exit(0); } } } class TicketStoreSale { public static void main(String[] args) { Tickets t = new Tickets(10); Thread t1 = new Thread(new Productor(t)); Thread t2 = new Thread( new Costomer(t)); t1.start(); t2.start(); } }
方式三:在JDK1.5中提供了多线程升级解决方案。
将同步Synchronized替换成显式的Lock操作。
将Object中的wait,notify,notifyAll,替换成了Conditon对象。
该对象可以对Lock锁,进行获取。
该示例中,实现了本方只唤醒对方操作。
import java.util.concurrent.locks.*; class Tickets //定义(资源)票类 { protected int size;//总票数 int number=0; //票号 Boolean available=false;//表示当前是否有票可售 public Tickets(int size) { this.size = size; } Lock lock = new ReentrantLock(); //创建锁 Condition notFull = lock.newCondition(); //创建未满状态 Condition notEmpty = lock.newCondition();//创建未空状态 public void store() throws InterruptedException //同步方法,实现存票功能 { lock.lock(); try { if(available) //如果线程还有票可售,则存票线程等待 notEmpty.await(); System.out.println(Thread.currentThread().getName()+"存入第【"+(++number)+"】张票"); available = true; notFull.signal();//存票后,唤醒售票线程开始售票 } finally { lock.unlock(); //释放锁资源 } } public void sale() throws InterruptedException //同步方法,实现售票功能 { lock.lock(); try { if(!available) //如果线程没有票可售,则售票线程等待 notFull.await(); System.out.println(Thread.currentThread().getName()+"售出第【"+(number)+"】张票"); available = false; notEmpty.signal(); //售票后,唤醒存票线程开始存票 } finally { lock.unlock(); //释放锁资源 } } } class Productor implements Runnable //实现一个接口,生产者(存票)线程类 { private Tickets t; public Productor(Tickets t) { this.t = t; } public void run() { while(true) { if(t.number<t.size) try { t.store(); } catch (InterruptedException e) { e.printStackTrace(); } else System.exit(0); } } } class Costomer implements Runnable //实现一个接口,消费者(售票)线程类 { private Tickets t; public Costomer(Tickets t) { this.t = t; } public void run() { while(true) { if(t.number<=t.size) try { t.sale(); } catch (InterruptedException e) { e.printStackTrace(); } else System.exit(0); } } } class TicketStoreSaleLock { public static void main(String[] args) { Tickets t = new Tickets(10); Thread t1 = new Thread(new Productor(t)); Thread t2 = new Thread( new Costomer(t)); t1.start(); t2.start(); } }
程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式!