• 对于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。静态方法的锁对象是类的字节码文件对象。

  • 相关阅读:
    插入排序
    python -- 给电视剧重命名
    程序员你为什么迷茫?
    如何把自己打造成技术圈的 papi 酱
    GitHub中国区前100名到底是什么样的人?
    Python+opencv 图像拼接
    VS2015 新Web项目(C#6)出现CS1617错误的解决
    .Net Task<T>的一种比较神奇的卡死情况(Wait/Result卡死, await能得到结果)
    Xamarin Android自学和实践步骤
    跨过几个坑,终于完成了我的第一个Xamarin Android App!
  • 原文地址:https://www.cnblogs.com/liyinggang/p/4976034.html
Copyright © 2020-2023  润新知