简单卖票程序初步认识多线程

以下只是认识线程的开始,以static表示几个线程控制同一个变量增减的情形开始逐步深入多线程依次

特别注意;

Thread类才是和线程相关的,而Runnable接口本身和线程无直接关系

Thread类本身实现了Runnable接口

Runnable 接口中仅仅定义了一个抽象方法run

Runnable接口本身就是定义了一个代码存放的位置(需要执行的方法存放在run方法中)

Thread类实现Runnable接口作用只是为线程中运行的代码确定了一个存放位置,换句话说:

线程Thread对象相当于一辆汽车,Runnable相当于一个可以存放物品的形状大小等可随机变化的箱子,里面可以盛装货物,

而目标运行的代码(我们存放在run方法中的代码)相当于要运行的货物,想要使用汽车(Thread)运行货物(代码)到某个地方,必须将货物存放在指定的箱子(Runnable接口的run()方法)中.

特别注意本实例运行的结果分析:

1、因为是多线程,所以出票的结果数目不是完全从100依次降到1;

2、最后的结果中,并非1打印到最后,是因为电脑为多核CPU,处理时并非完全理论中的依次降低的结果

因为Windows一边调用Java虚拟机执行票数减少1的程序,一边调用控制台,打印出票结果,在此显示的结果故而如图


package practiceMySelf;

/**
 * 需求:简单的卖票程序
 * 多个窗口同时卖
 * */
public class Ticket extends  Thread{
	//用tick变量赋值100,表示存储100张票
	//private int tick=100;
	//static 用于控制以下程序中,几个线程共同控制一个变量的增减
	//因为是几个窗口共同卖100张票
	private static int tick=100;
	
	public void run(){
		while(true){
			if(tick>0){
				//票每卖出一张减少1
				System.out.println(Thread.currentThread().getName()+"..sales:"+tick--);
			}
		}
	}
}
class ThreadDemo1{
	public static void main(String[] args){
		//创建4个线程,表示四个同时开卖的窗口
		Ticket t1=new Ticket();
		Ticket t2=new Ticket();
		Ticket t3=new Ticket();
		Ticket t4=new Ticket();
		//开始售票
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
		
	}
}

package practiceMySelf;
/**
 * 需求:简单的卖票程序
 * 多个窗口同时卖
 * 
 * 创建线程的第二种方式,实现Runable接口
 * 步骤:
 * 1、定义类实现Runnable接口
 * 2、覆盖Runnable接口中的run方法
 *      将线程要运行的代码存放在该run方法中。
 * 3、通过Thread类建立线程对象
 * 4、将Runnable接口的子类对象作为实际参数传递给Thread的构造方法
 *      为什么要将Runnable接口的子类对象传递给Thread的构造函数?
 *       因为,自定定义的run方法所属的对象时Runnable接口口的子类
 *       所以要让线程去指定指定对象的run方法
 *5、调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
 * */


public class Ticket  implements Runnable{//extends  Thread{
	//用tick变量赋值100,表示存储100张票
	//private int tick=100;
	//static 用于控制以下程序中,几个线程共同控制一个变量的增减
	//因为是几个窗口共同卖100张票
	private static int tick=100;
	
	public void run(){
		while(true){
			if(tick>0){
				//票每卖出一张减少1
				System.out.println(Thread.currentThread().getName()+"..sales:"+tick--);
			}
		}
	}
}
class ThreadDemo1{
	public static void main(String[] args){
//		//创建4个线程,表示四个同时开卖的窗口
//		Ticket t1=new Ticket();
//		Ticket t2=new Ticket();
//		Ticket t3=new Ticket();
//		Ticket t4=new Ticket();
//		//开始售票
//		t1.start();
//		t2.start();
//		t3.start();
//		t4.start();
		
		Ticket t=new Ticket();
		//创建4个线程,表示四个同时开卖的窗口
				Thread t1=new Thread(t);
				Thread t2=new Thread(t);
				Thread t3=new Thread(t);
				Thread t4=new Thread(t);
				//开始售票
				t1.start();
				t2.start();
				t3.start();
				t4.start();
			
	}
}
	

以上代码中可发现:

创建线程的方式有两种,继承Thread类和实现Runnable接口两种,有何区别呢?

实现方式好处:避免了继承的局限性,Java中继承为单一继承机制

在定义(创建)线程时,建议使用实现的方式


两种方式区别:

继承Thread:线程代码存放在Thread子类的run方法中

实现Runnable:线程代码存放在接口的子类的run方法中


线程安全问题 ——线程共享数据不合理问题

实例情况如下代码,运行结果可能会出现票数为0的情况(可能在多次试验过程中也未出现非法数据如0  -1等问题,但一定存在可能性)



package practiceMySelf;
class Ticket1  implements Runnable{//extends  Thread{
	//用tick变量赋值100,表示存储100张票
	//private int tick=100;
	//static 用于控制以下程序中,几个线程共同控制一个变量的增减
	//因为是几个窗口共同卖100张票
	private int tick=100;
	
	public void run(){
		while(true){
			if(tick>0){
                                //以下让线程睡眠,就是为了模拟线程不安全情形的状态
				try {Thread.sleep(10);} 
				catch (InterruptedException e) {e.printStackTrace();}
				//票每卖出一张减少1
				System.out.println(Thread.currentThread().getName()+"..sales:"+tick--);
			}
		}
	}
}
class ThreadDem{
	public static void main(String[] args){
//		//创建4个线程,表示四个同时开卖的窗口
//		Ticket t1=new Ticket();
//		Ticket t2=new Ticket();
//		Ticket t3=new Ticket();
//		Ticket t4=new Ticket();
//		//开始售票
//		t1.start();
//		t2.start();
//		t3.start();
//		t4.start();
		
		Ticket1 t=new Ticket1();
		//创建4个线程,表示四个同时开卖的窗口
				Thread t1=new Thread(t);
				Thread t2=new Thread(t);
				Thread t3=new Thread(t);
				Thread t4=new Thread(t);
				//开始售票
				t1.start();
				t2.start();
				t3.start();
				t4.start();
			
	}
}
/**
 * 需求:简单的卖票程序
 * 经过运行发现,可能会出现打印出0  -1  -2号票的情形
 *多线程的运行出现了安全问题
 *问题的原因:
 * 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有
 *  执行完,另一个线程参与进来执行,导致共享数据的错误
 *  
 *  解决办法:
 *     对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程
 *     不可以参与执行;
 *     
 * Java对于多线程的安全问题提供了专业的解决方式:
 * 就是同步代码块
 * synchronized(对象){
 * 需要被同步的代码
 * }    
 *
 * */
	
package practiceMySelf;


 class TicektSecrety {


}


package practiceMySelf;


/**
 * 需求:简单的卖票程序
 * 经过运行发现,可能会出现打印出0  -1  -2号票的情形
 *多线程的运行出现了安全问题
 *问题的原因:
 * 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有
 *  执行完,另一个线程参与进来执行,导致共享数据的错误
 *  
 *  解决办法:
 *     对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程
 *     不可以参与执行;
 *     
 * Java对于多线程的安全问题提供了专业的解决方式:
 * 就是同步代码块
 * synchronized(对象){
 * 需要被同步的代码
 * }    
 * 对象如同锁,持有锁的线程可以在同步中执行
 * 没有持有锁的线程及时获取CPU的执行权,也进不去,因为没有获取锁
 * 
 * 火车上的卫生间--经典举例:
 * 同步现象如同火车上同一节列车上抢该列车上的卫生间
 * 
 * 同步的前提:
 * 1、必须要有两个或者两个以上的线程
 * 2、必须是多个线程使用同一个锁
 * 必须保证同步中只能有一个线程在运行
 * 
 * 同步的好处:解决了多个线程的安全问题
 * 弊端:多个线程需要判断锁,较为消耗资源
 * 越安全越麻烦
 *

 * */

//以下person类是在问题分析过程中产生的垃圾,体现了思路一步步来的经过,用于帮助自身后期便于理解用

// class Person{
//  
// public Person(){super();}
// }


class Ticket1  implements Runnable{//extends  Thread{
//用tick变量赋值100,表示存储100张票
//private int tick=100;
//static 用于控制以下程序中,几个线程共同控制一个变量的增减
//因为是几个窗口共同卖100张票
private int tick=100;
//Person p=new Person();
Object obj=new Object();
public void run(){

while(true){
//synchronized(p){
synchronized(obj){
if(tick>0){
try {Thread.sleep(10);} 
catch (InterruptedException e) {e.printStackTrace();}
//票每卖出一张减少1
System.out.println(Thread.currentThread().getName()+"..sales:"+tick--);
}
}

}
}
}
class ThreadDem{
public static void main(String[] args){
// //创建4个线程,表示四个同时开卖的窗口
// Ticket t1=new Ticket();
// Ticket t2=new Ticket();
// Ticket t3=new Ticket();
// Ticket t4=new Ticket();
// //开始售票
// t1.start();
// t2.start();
// t3.start();
// t4.start();

Ticket1 t=new Ticket1();
//创建4个线程,表示四个同时开卖的窗口
Thread t1=new Thread(t);
Thread t2=new Thread(t);
Thread t3=new Thread(t);
Thread t4=new Thread(t);
//开始售票
t1.start();
t2.start();
t3.start();
t4.start();

}
}

                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值