对于JAVA多线程卖票小程序的理解
昨天把多线程重新看了一遍,发现自己还是有许多需要理解的地方,现在写一篇总结。
一:利用继承Thread类会出现的问题:
public class SellTicketsThread extends Thread { private int tickets = 10; public SellTicketsThread(String name) { super(name); } @Override public void run() { while (true) { if(tickets<=0) break; synchronized (this) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if (tickets > 0) { System.out.println(Thread.currentThread().getName() + "卖出第" + tickets-- + "张票"); } } } } } public class SellTicketsThreadDemo { public static void main(String[] args) { SellTicketsThread t1 = new SellTicketsThread("窗口1"); SellTicketsThread t2 = new SellTicketsThread("窗口2"); SellTicketsThread t3 = new SellTicketsThread("窗口3"); t1.start(); t2.start(); t3.start(); } }
这样的话看上去是用了同步锁锁住了对象,但运行结果却是不符合逻辑的。三个窗口共卖了30张票。
窗口2卖出第10张票 窗口1卖出第10张票 窗口3卖出第10张票 窗口3卖出第9张票 窗口2卖出第9张票 窗口1卖出第9张票 窗口3卖出第8张票 窗口1卖出第8张票 窗口2卖出第8张票 窗口2卖出第7张票 窗口3卖出第7张票 窗口1卖出第7张票 窗口2卖出第6张票 窗口1卖出第6张票 窗口3卖出第6张票 窗口2卖出第5张票 窗口1卖出第5张票 窗口3卖出第5张票 窗口2卖出第4张票 窗口3卖出第4张票 窗口1卖出第4张票 窗口2卖出第3张票 窗口1卖出第3张票 窗口3卖出第3张票 窗口2卖出第2张票 窗口1卖出第2张票 窗口3卖出第2张票 窗口2卖出第1张票 窗口3卖出第1张票 窗口1卖出第1张票
二:利用Runnale接口实现
package SellTickets; public class SellTicketsThread implements Runnable{ private int tickets = 10; @Override public void run() { while(true){ if(tickets<=0) break; synchronized(this){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if(tickets>0){ System.out.println(Thread.currentThread().getName()+"卖出第"+tickets--+"张票"); } } } } } public class SellTicketsThreadDemo { public static void main(String[] args) { SellTicketsThread st = new SellTicketsThread(); Thread t1 = new Thread(st,"窗口一"); Thread t2 = new Thread(st,"窗口二"); Thread t3 = new Thread(st,"窗口三"); t1.start(); t2.start(); t3.start(); } }
窗口一卖出第10张票 窗口一卖出第9张票 窗口一卖出第8张票 窗口三卖出第7张票 窗口二卖出第6张票 窗口二卖出第5张票 窗口三卖出第4张票 窗口三卖出第3张票 窗口三卖出第2张票 窗口三卖出第1张票
这样就不会有问题了,因为三个线程共享的是同一个Runnable开辟的内存.网上几乎都是用的这种方法,能不能不用Runnable接口也能实现这个效果呢??接下来是用Thread实现的两种方式,如有错误之处还请指正.
三:在继承Thread的类中定义静态变量和静态方法,将锁加在静态方法上,让多个线程共享。
public class SellTicketsThread extends Thread { public SellTicketsThread(String name){ super(name); } public SellTicketsThread(){ } private static int tickets =10; public synchronized static void take(){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if(tickets>0){ System.out.println(Thread.currentThread().getName() + "卖出第" + tickets-- + "张票"); } } @Override public void run() { while(true){ take(); } } } public class SellTicketsThreadDemo { public static void main(String[] args) { SellTicketsThread t1 = new SellTicketsThread("窗口1"); SellTicketsThread t2 = new SellTicketsThread("窗口2"); SellTicketsThread t3 = new SellTicketsThread("窗口3"); t1.start(); t2.start(); t3.start(); } }
窗口1卖出第10张票 窗口1卖出第9张票 窗口3卖出第8张票 窗口3卖出第7张票 窗口3卖出第6张票 窗口2卖出第5张票 窗口2卖出第4张票 窗口3卖出第3张票 窗口1卖出第2张票 窗口1卖出第1张票
四:定义一个锁对象,让多个线程共同用同一个锁,同时将共享变量定义成静态的。
public class SellTicketsThread extends Thread { Object o =null; private static int tickets = 10; public SellTicketsThread(String name,Object o){ super(name); this.o = o; } public SellTicketsThread(){ } @Override public void run() { while(true){ while(true){ if(tickets<=0) break; synchronized(o){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if(tickets>0){ System.out.println(Thread.currentThread().getName()+"卖出第"+tickets--+"张票"); } } } } } } public class SellTicketsThreadDemo { public static void main(String[] args) { Object o = new Object();//共同的锁 SellTicketsThread t1 = new SellTicketsThread("窗口1",o); SellTicketsThread t2 = new SellTicketsThread("窗口2",o); SellTicketsThread t3 = new SellTicketsThread("窗口3",o); t1.start(); t2.start(); t3.start(); } }
窗口1卖出第10张票 窗口1卖出第9张票 窗口1卖出第8张票 窗口3卖出第7张票 窗口3卖出第6张票 窗口3卖出第5张票 窗口3卖出第4张票 窗口2卖出第3张票 窗口2卖出第2张票 窗口2卖出第1张票
还需要注意的是,同步代码块的锁对象是任意对象。所以可以用Object做为一个锁。而同步方法(非静态)的锁对象是 this。静态方法的锁对象是类的字节码文件对象。