多线程的经典案例(卖票问题)

转帖请注明本文出自weimeig的博客(http://blog.csdn.net/weimeig/article/details/79512965),请尊重他人的辛勤劳动成果,谢谢

应朋友们反馈的JAVA基础薄弱的问题,决定出一套完整的JAVA基础教程,帮助大家复习,巩固JAVA基础,今天要讲的是多线程的经典案例。

卖票问题

class Xc implements Runnable{
	
public int chepiao = 100;
	public void run(){
		while (true) {
			if(chepiao>0){
				System.out.println("第" + Thread.currentThread().getName() + "个车站正在卖出第" + (101-chepiao) + "张车票");
				--chepiao;
			}else{
				break;
			}
		}
	}
}
public class XianCheng {
	public static void main(String [] args){
		Thread Xc1 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源
		Xc1.start();
		Thread Xc2 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源
		Xc2.start();
	}
}


通过代码,我们不难发现,在运行的过程中出现了错误,因为Xc1和Xc2各自都生成了100张车票,而车票没有共享,此时,我们需要将车票定义为静态变量,使得两线程在竞争售票的过程中,共享车票,于是,将常量定义为静态常量,用static修饰:

public static int chepiao = 100;
class Xc implements Runnable{
	
public static int chepiao = 100;
	public void run(){
		while (true) {
			if(chepiao>0){
				System.out.println("第" + Thread.currentThread().getName() + "个车站正在卖出第" + (101-chepiao) + "张车票");
				--chepiao;
			}else{
				break;
			}
		}
	}
}
public class XianCheng {
	public static void main(String [] args){
		Thread Xc1 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源
		Xc1.start();
		Thread Xc2 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源
		Xc2.start();
	}
}

但是很快的,我们又发现了新问题,因为线程在竞争的过程中,CPU的切换是非常快的,可能线程1正好执行完--maipiao的时候,线程已经切换到了线程2,此时--maipiao又再执行了一次,导致跳过了一张票没有卖出,或者,当线程1恰好正好将要执行--maipiao但还没执行的时候,线程已经切换到了线程2,此时因为线程1并没有进行--maipiao操作,线程2卖出了重复的同一张票以后,才执行了--maipiao,导致出现了同一张票重复销售的情况。

此时,我们需要引入线程锁的概念,以解决线程的同步问题。

第一种写法:

class Xc implements Runnable{
	public static int chepiao = 100;
	//synchronized的作用是,让它所管辖的代码部分,要么全部执行完,要么全部不执行,synchronized既可修饰代码块,又可以修饰函数
//	如果是锁整个方法,可以在方法内加锁,表达上比如public synchronized void run(){,但对于此案例,是两个线程之间竞争售票,因此不适宜锁起来整个方法
	//如果synchronized是锁起来整个方法的,synchronized修饰函数不需要传入字符串参数,相当于默认是this
	public void run(){
		while (true) {
			synchronized (" ") {//在需要加锁保证完整运行的代码块旁边加上synchronized (" "){}包裹代码,即可锁起来该部分代码,()内的字符串随意定义
				if(chepiao>0){
					System.out.println("第" + Thread.currentThread().getName() + "个车站正在卖出第" + (101-chepiao) + "张车票");
					--chepiao;
				}else{
					break;
				}
			}
		}
	}
}
public class XianCheng {
	public static void main(String [] args){
		Thread Xc1 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源
		Xc1.start();
		Thread Xc2 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源
		Xc2.start();
	}
}

第二种写法:

class Xc implements Runnable{
	public static int chepiao = 100;
	public static String str = new String("weimeig");//提取出来提高可维护性,同时定义为static静态变量,使得str是公共的
							//如果不定义成static静态,则两个线程各自有各自的str,那么大家竞争的就不是同一个资源
	public void run(){
		while (true) {
			synchronized (str) {//若不定义为static静态,则两个线程的str是线程自己的,而不是公共的,因为这种写法,初始化的str写在了锁的外面
				if(chepiao>0){
					System.out.println("第" + Thread.currentThread().getName() + "个车站正在卖出第" + (101-chepiao) + "张车票");
					--chepiao;
				}else{
					break;
				}
			}
		}
	}
}
public class XianCheng {
	public static void main(String [] args){
		Thread Xc1 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源
		Xc1.start();
		Thread Xc2 = new Thread(new Xc());//模拟两个车站在卖车票,竞争共同的线程资源
		Xc2.start();
	}
}



你可能感兴趣的:(JAVA)