以电影院售票为例
方案一:同步代码块
public class Cinerma { int tickets = 50;//剩余票数 Object lock = new Object();//可以看做钥匙对象 //卖票函数 public void sellTicket(int num,int id) throws InterruptedException {//本函数一般跑在子线程中,所以在执行tickets = tickets -num;时会发生线程危险 if(tickets>=num){ System.out.println(Thread.currentThread().getName()+id+":啊哈,有票,让我来跟售票员墨迹一会");//注意此处子线程的id Thread.sleep(200); System.out.println(Thread.currentThread().getName()+id+":墨迹完了,我要买票了"); synchronized(lock){//正式买票,同步起来 if(tickets>=num){ Thread.sleep(200); tickets = tickets -num; System.out.println(Thread.currentThread().getName()+id+":买了"+num+"张,剩余票数"+tickets); }else{ System.out.println(Thread.currentThread().getName()+id+":fuck=fuck=fuck=fuck=fuck,刚刚还有票的"); } } }else{ System.out.println("没票了咱走吧"); }
方案二:使用加锁对象,ReentrantLock
ReentrantLock reentrantLock = new ReentrantLock();//放在成员里就好 //询问处的函数,一次只能一个线程来问,都排队 public void question(int id) throws InterruptedException{//运行在子线程中的方法 reentrantLock.lock();//此处开始同步 System.out.println(Thread.currentThread().getName()+id+":来买爆米花了"); Thread.sleep(3000); System.out.println(Thread.currentThread().getName()+id+":买完了"); reentrantLock.unlock();//此处停止同步 }
调用方法:
Cinerma cinerma = new Cinerma(); Thread buyticketThread1 = new BuyTicketThread("情侣", 2, cinerma);//thread的名字,买票数,电影院对象 Thread buyticketThread2 = new BuyTicketThread("单身狗", 1, cinerma); Thread askThread = new AskQuestionThread("爆米花",cinerma); buyticketThread1.start(); buyticketThread2.start(); askThread.start(); class BuyTicketThread extends Thread{//买票线程 int num =0; Cinerma cinerma; public BuyTicketThread(String name,int num,Cinerma cinerma){ this.num = num; this.cinerma = cinerma; this.setName(name);//设置线程名 } @Override public void run() { // TODO Auto-generated method stub try { for (int i = 0; i < 1000; i++) {//买1000张票 cinerma.sellTicket(num,i); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public class AskQuestionThread extends Thread{//咨询线程 Cinerma cinerma ; String name; public AskQuestionThread(String name,Cinerma cinerma){ this.name = name; this.cinerma = cinerma; } @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < 3; i++) { try { cinerma.question(i); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
方案3:notify()和wake()
建立一个场景,一位母亲有三个孩子,需要给他们做饭,一次只能做一个,每个孩子都要不停的吃饭,做饭和吃饭都需要时间,循环往复
首先建立一个厨房对象,这个对象是最主要的,里面有做饭和吃饭两个方法,重点是,这两个方法都要用synchronized修饰
public class Kitchen { int food = 0;//剩余的饭 //做饭函数 public synchronized void cook() throws InterruptedException{//注意这个函数被synchronized给修饰了 if(food>0){//如果当前还有饭 wait();//妈妈线程等待,等待孩子线程notify她,函数会停留在这一句不动,直到有notify //如果被notify了,则执行下面的 food = food +1;//做饭 System.out.println("做完饭后一共剩余"+food); System.out.println(Thread.currentThread().getName()+":饭做好了"); notifyAll();//呼叫孩子线程 }else{//如果当前没剩饭了 food = food +1; System.out.println(food); System.out.println(Thread.currentThread().getName()+":饭做好了"); notifyAll();//通知孩子线程 } <pre name="code" class="java"> System.out.println("通知完孩子后剩余"+food);
Kitchen kitchen = new Kitchen(); Thread motherThread = new Mother(kitchen); Thread chilThread1 = new Childrens("大娃", kitchen); Thread chilThread2 = new Childrens("二娃", kitchen); Thread chilThread3 = new Childrens("三娃", kitchen); motherThread.start(); chilThread1.start(); chilThread2.start(); chilThread3.start(); //下面是三个线程的定义 public class Childrens extends Thread{ Kitchen kitchen; public Childrens(String name,Kitchen kitchen){ this.kitchen = kitchen; this.setName(name); } @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < 3; i++) { try { kitchen.eat(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"吃饱了"); } } public class Mother extends Thread{ Kitchen kitchen; public Mother(Kitchen kitchen){ this.kitchen = kitchen; } @Override public void run() { // TODO Auto-generated method stub while (true) { try { kitchen.cook(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }