多线程(二)

需求:

某电影院目前正在上映贺岁大片,共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票。

两种方式实现

继承Thread类

实现Runnable接口

//1:继承方式


class SellTicket extends Thread {
	SellTicket(){super();}
	SellTicket(String name){super(name);}
	private static int tickets=100;
	public void run() {
	while(true){
		if(tickets>0){
			System.out.println(getName()+"正在售出第"+tickets--+"张票");
		}
	}
    }
}

public class SellTicketDemo {

	public static void main(String[] args) {
		SellTicket st1=new SellTicket("窗口1");
		SellTicket st2=new SellTicket("窗口2");
		SellTicket st3=new SellTicket("窗口3");
		st1.start();
		st2.start();
		st3.start();
	}

}


//实现Runnable接口方式

class SellTicket implements Runnable {
	private int tickets=100;
	public void run() {
	while(true){
		if(tickets>0){
			System.out.println(Thread.currentThread().getName()+"正在售出第"+tickets--+"张票");
		}
	}
    }
}

public class SellTicketDemo {

	public static void main(String[] args) {
		SellTicket st=new SellTicket();
		Thread st1 =new Thread(st,"窗口1");
		Thread st2 =new Thread(st,"窗口2");
		Thread st3 =new Thread(st,"窗口3");
		st1.start();
		st2.start();
		st3.start();
	}

}



在这里出现一个问题,在真正的买票过程中,我们的数据不可能实时传输,这样我们就需要让其售票后停顿一下

很显然,结果出现了重复的情况,这是为什么呢?

问题:

相同的票出现多次

         CPU的一次操作必须是原子性的(简单的操作)

还出现了负数的票

          随机性和延迟导致的

注意

•线程安全问题在理想状态下,不容易出现,但一旦出现对软件的影响是非常大的。

解决线程安全问题的基本思想

首先想为什么出现问题?(也是我们判断是否有问题的标准)

     •是否是多线程环境

     •是否有共享数据

     •是否有多条语句操作共享数据

如何解决多线程安全问题呢?

     •基本思想:让程序没有安全问题的环境。

     •怎么实现呢?

     •把多个语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可。

同步代码块

•格式:

  synchronized(对象){需要同步的代码;}

•同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。

同步代码块的对象可以是哪些呢?

锁:synchronized

        A:同步代码块
            synchronized(对象) {
                需要被同步的代码;
            }
            这里的锁对象可以是任意对象。

public class SellTicket implements Runnable {
	private int tickets=100;
	//线程安全 锁是关键
	Object obj=new Object();
	public void run() {
	while(true){
		synchronized(obj){
		if(tickets>0){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"正在售出第"+tickets--+"张票");
		 }
		}
	}
    }
}

同步的前提:
     1:多个线程
     2:多个线程使用的是同一个锁对象
同步的好处:
     同步的出现解决多线程的安全问题
同步的弊端:
    当线程很多的时候,每一个线程都会去判断同步上的锁,这是很浪费资源的,无形中会降低程序的运行效率

package Test_07;
class Demo{}//自己随意建的类
public class SellTicket implements Runnable {
	
	
	
	private static int tickets=100;
	Object obj=new Object();
	Demo d=new Demo();
	
	
 使用同步代码块   obj做锁    
//	public void run() {
//		while(true){
//				//synchronized(obj){
//				synchronized(d){
//				if(tickets>0){
//						try {
//							Thread.sleep(1000);
//						} catch (InterruptedException e) {
//							e.printStackTrace();
//						}
//						System.out.println(Thread.currentThread().getName()+"正在售出第"+tickets--+"张票");
//					 }
//					}
	
//	同步代码块   d做锁	
//	public void run() {
//		while(true){
//				synchronized(d){
//				if(tickets>0){
//						try {
//							Thread.sleep(1000);
//						} catch (InterruptedException e) {
//							e.printStackTrace();
//						}
//						System.out.println(Thread.currentThread().getName()+"正在售出第"+tickets--+"张票");
//					 }
//					}

	
// 3现在我们将第二个同步块打包成方法,试试看可不可以运行
//	private void FunctionSynchronized() {
//		synchronized(d){
//			if(tickets>0){
//					try {
//						Thread.sleep(1000);
//					} catch (InterruptedException e) {
//						e.printStackTrace();
//					}
//					System.out.println(Thread.currentThread().getName()+"正在售出第"+tickets--+"张票");
//				 }
//				}
//	}
	
	//如果一个方法一进去就看到了代码被同步了,那么我就再想能不能把这个同步加在方法上呢?
//	 private synchronized void sellTicket() {
//			if (tickets > 0) {
//			try {
//					Thread.sleep(100);
//			} catch (InterruptedException e) {
//					e.printStackTrace();
//			}
//			System.out.println(Thread.currentThread().getName()
//						+ "正在出售第" + (tickets--) + "张票 ");
//			}
//	}
	
	
	
	public void run() {
	while(true){
		int x=0;
		if(x%2==0){
			//synchronized(obj){
			synchronized(d){
			if(tickets>0){
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"正在售出第"+tickets--+"张票");
				 }
				}
		}else{
//				synchronized(d){
//					if(tickets>0){
//							try {
//								Thread.sleep(1000);
//							} catch (InterruptedException e) {
//								e.printStackTrace();
//							}
//							System.out.println(Thread.currentThread().getName()+"正在售出第"+tickets--+"张票");
//						 }
//						}
//			}
			
			
			FunctionSynchronized();
		}
		x++;
}
}
	private static synchronized void FunctionSynchronized() {
			if(tickets>0){
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"正在售出第"+tickets--+"张票");
				 }
	}
}

public class SellTicketDemo {

	public static void main(String[] args) {
		SellTicket st=new SellTicket();
		Thread st1 =new Thread(st,"窗口1");
		Thread st2 =new Thread(st,"窗口2");
		Thread st3 =new Thread(st,"窗口3");
		st1.start();
		st2.start();
		st3.start();
	}

}


 B:同步方法
      把同步加在方法上。这里的锁对象是this 
      private synchronized void FunctionSynchronized() {
            if(tickets>0){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在售出第"+tickets--+"张票");
                 }
    }
 C:静态同步方法
      把同步加在方法上。
      这里的锁对象是当前类的字节码文件对象(反射再讲字节码文件对象)    SellTicket.class

private static synchronized void FunctionSynchronized() {
            if(tickets>0){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在售出第"+tickets--+"张票");
                 }
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值