编程语言
首页 > 编程语言> > java中线程的一些相关概念,第6篇(线程间的通信)

java中线程的一些相关概念,第6篇(线程间的通信)

作者:互联网

java中线程的一些相关概念,第6篇(线程间的通信)

直接po代码和截图

我们根据一个案例来讲解线程间的通信的知识点!

买票的案例如下:

票价是5元

在卖票开始前,售票员身上有5元面值的钞票1张,10元面值的钞票0张,20元面值的钞票0张

有3个人去买票,3个人同时向同一个售票员买票,这3个人分别拿5元面值的钞票、10元面值的钞票、20元面值的钞票去买票,如果售票员身上的零钱不够时,就让买票的人先等待,等售票员身上的零钱够时,再卖票给买票的人

直接po代码和截图

TicketSeller类

package com.demo.threadmessage2;

//售票员类,演示线程间通信的案例
//主要是wait()、notify()、notifyAll()这3个函数,这3个函数都是Object类的方法
//sleep()是Thread类的方法
public class TicketSeller {
	
	//3种不同面值的钞票
	// 表示持有的三种面值的数目,初始情况是:5元面值的钞票1张,10元面值的钞票0张,20元面值的钞票0张
	int five = 1, ten = 0, twenty = 0;
	
	int ticketCount = 26; //当前余票的数量,当前有26张余票

	// 买票方法
	public synchronized void sellTicket(double money) {
		if (ticketCount > 0) {
		if (money == 5) {// 如果给的是5元
			five++; // 5元面值的钞票加1张
			System.out.println(Thread.currentThread().getName() + "给了售票员5元钱,售票1张,没有找零....");
			System.out.println("------现在售票员手上有5元面值的钞票" + five + "张,10元面值的钞票" + ten + "张,20元面值的钞票" + twenty + "张------");
		} else if (money == 10) {// 如果给的是10元
			int waitCount = 0; //等待次数
			while (five < 1) { //5元面值的钞票少于1张的话,无法找零
				waitCount++;
				System.out.println("尊敬的" + Thread.currentThread().getName() + ",您给了售票员" + money + "元,但是十分抱歉,目前售票员手中的零钱不够,暂时无法卖票给您,请您耐心等待,这是您第" + waitCount + "次等待#####");
				try {
					wait(); //当前线程处于等待状态,即线程挂起(线程处于挂起状态)
				System.out.println(Thread.currentThread().getName() + "第" + waitCount + "次等待结束,继续买票!!!!!!!!" );	
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			ten++; // 10元面值的钞票加1张
			five--; // 5元面值的钞票少1张
			System.out.println(Thread.currentThread().getName() + "给了售票员10元钱,售票1张,找零5元....");
			System.out.println("------现在售票员手上有5元面值的钞票" + five + "张,10元面值的钞票" + ten + "张,20元面值的钞票" + twenty + "张------");
		} else if (money == 20) {// 如果给的是20元
			int waitCount = 0; //等待次数
			while (ten < 1 || five < 1) { //只要5元面值的钞票或者10元面值的钞票,其中任何一种面值的钞票少于1张的话,就无法找零
				waitCount++;
				System.out.println("尊敬的" + Thread.currentThread().getName() + ",您给了售票员" + money + "元,但是十分抱歉,目前售票员手中的零钱不够,暂时无法卖票给您,请您耐心等待,这是您第" + waitCount + "次等待#####");
				try {
					wait(); //当前线程处于等待状态,即线程挂起(线程处于挂起状态)
				System.out.println(Thread.currentThread().getName() + "第" + waitCount + "次等待结束,继续买票*************************" );
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			twenty++; // 20元面值的钞票加1张
			ten--; // 10元面值的钞票少1张
			five--; // 5元面值的钞票少1张
			System.out.println(Thread.currentThread().getName() + "给了售票员20元钱,售票1张,找零15元....");
			System.out.println("------现在售票员手上有5元面值的钞票" + five + "张,10元面值的钞票" + ten + "张,20元面值的钞票" + twenty + "张------");
		}
		ticketCount--; //当前余票数减去1张
		notifyAll(); // 通知/唤醒当前挂起的线程进入就绪状态
		}
	}

}

Person类

package com.demo.threadmessage2;

//观众类
public class Person implements Runnable{
	
	//当前手上有的金额
	double money;
	
	//可以理解成,一个观众就是一个线程
	//(我们的案例就是演示多个观众线程同时操作的是同一个售票员对象)
	
	//售票员对象
	TicketSeller ticketSeller;

	public Person(TicketSeller ticketSeller, double money) {
		this.ticketSeller = ticketSeller;
		this.money = money;
	}

	@Override
	public void run() {
		ticketSeller.sellTicket(money);
	}
	
	

}

Test类

package com.demo.threadmessage2;

public class Test {

	public static void main(String[] args) {
		//创建一个售票员对象
		TicketSeller ticketSeller = new TicketSeller();
		System.out.println("#################卖票开始前#################");
		int beforeSellTicketCount = ticketSeller.ticketCount;// 卖票开始前的余票数量
		System.out.println("==========售票员对象手中目前有" + beforeSellTicketCount + "张余票==========");
		System.out.println("*****售票员对象手中目前有5元面值的钞票" + ticketSeller.five + "张," + "10元面值的钞票" + ticketSeller.ten + "张," + "20元面值的钞票" + ticketSeller.twenty + "张*****");
		System.out.println(".....................开始卖票了.....................");
		//可以理解成,一个观众就是一个线程
		//创建3个观众对象,3个观众对象同时向同一个售票员对象买票(即3个线程同时操作同一个对象)
		Person twentyPerson = new Person(ticketSeller, 20); // 拿20元钱的观众
		Person tenPerson = new Person(ticketSeller, 10); // 拿10元钱的观众
		Person fivePerson = new Person(ticketSeller, 5); // 拿5元钱的观众
		
		//给3个观众线程设置3个名字
		Thread twentyThread = new Thread(twentyPerson, "贰拾元哥");
		Thread tenThread = new Thread(tenPerson, "拾元哥");
		Thread fiveThread = new Thread(fivePerson, "伍元哥");
		
		//启动线程
		twentyThread.start();
		tenThread.start();
		fiveThread.start();
		
		//可以通过调整启动的先后顺序,来进行测试,以下是拿5元钱的人先启动,拿10元钱的人后启动,拿20元钱的人最后启动
		//以下3行代码,有可能是拿5元钱的人先买票,拿10元钱的人后买票,拿20元钱的人最后买票(我是说有可能,具体要看CPU的时间片)
//		fiveThread.start();
//		tenThread.start();
//		twentyThread.start();
		
		//主线程睡眠3秒,以使其他两个线程先执行完
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("**************卖票结束....最终的卖票结果如下:**************");
		System.out.println("总共卖出" + (beforeSellTicketCount - ticketSeller.ticketCount) + "张票,售票员对象手中目前还剩" + ticketSeller.ticketCount + "张余票");
		System.out.println("售票员对象手中目前有5元面值的钞票" + ticketSeller.five + "张," + "10元面值的钞票" + ticketSeller.ten + "张," + "20元面值的钞票" + ticketSeller.twenty + "张");
	}

}

运行结果如下:

Test2类

package com.demo.threadmessage2;

public class Test2 {

	public static void main(String[] args) {
		//创建一个售票员对象
		TicketSeller ticketSeller = new TicketSeller();
		System.out.println("#################卖票开始前#################");
		int beforeSellTicketCount = ticketSeller.ticketCount;// 卖票开始前的余票数量
		System.out.println("==========售票员对象手中目前有" + beforeSellTicketCount + "张余票==========");
		System.out.println("*****售票员对象手中目前有5元面值的钞票" + ticketSeller.five + "张," + "10元面值的钞票" + ticketSeller.ten + "张," + "20元面值的钞票" + ticketSeller.twenty + "张*****");
		System.out.println(".....................开始卖票了.....................");
		//可以理解成,一个观众就是一个线程
		//创建2个观众对象,2个观众对象同时向同一个售票员对象买票(即2个线程同时操作同一个对象)
		Person twentyPerson = new Person(ticketSeller, 20); // 拿20元钱的观众
		Person fivePerson = new Person(ticketSeller, 5); // 拿5元钱的观众
		
		/**
		 * 有这么一种情况:
		 * 就是拿着20元钱的人去售票员那里买票,然后售票员,零钱不够,然后拿着20元钱的人就等着,然后,有一个拿
		 * 着5元钱的人去售票员那里买票,售票员卖出了一张票,然后售票员现在手上有2张5元的,0张10元的,0张20元的,然
		 * 后拿着20元钱的人继续去售票员那里买票,然后售票员手上的零钱还是不够,然后拿着20元钱的人就一直等着,一直等啊等,以下代
		 * 码就是模拟这种情况
		 * 
		 * 如果拿20元钱的人先买票,那就会进入第1次等待,在等待的过程中,此时,拿5元钱的人去买票,拿5元钱的人买到票之
		 * 后,拿20元钱的人再次去买票,此时,拿20元钱的人会进入第2次等待,然后一直等待,一直等,一直等到地老天荒
		 * 
		 * 
		 * 
		 */
		//给2个观众线程设置2个名字
		Thread twentyThread = new Thread(twentyPerson, "贰拾元哥");
		Thread fiveThread = new Thread(fivePerson, "伍元哥");
		
		//启动线程
		twentyThread.start();
		fiveThread.start();
		
	/**
	 * 
	 * 如果拿5元钱的人先买票,拿5元钱的人买到票之后,此时,拿20元钱的人去买票,此
	 * 时,拿20元钱的人会进入第1次等待,然后一直等待,一直等,一直等到地老天荒
	 * 	
	 */
		//可以通过调整启动的先后顺序,来进行测试,以下是拿5元钱的人先启动,拿20元钱的人后启动
		//以下两行代码,有可能是拿5元钱的人先买票,拿20元钱的人后买票(我是说有可能,具体要看CPU的时间片)
//		fiveThread.start();
//		twentyThread.start();
		
		//主线程睡眠3秒,以使其他两个线程先执行完
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("**************卖票结束....最终的卖票结果如下:**************");
		System.out.println("总共卖出" + (beforeSellTicketCount - ticketSeller.ticketCount) + "张票,售票员对象手中目前还剩" + ticketSeller.ticketCount + "张余票");
		System.out.println("售票员对象手中目前有5元面值的钞票" + ticketSeller.five + "张," + "10元面值的钞票" + ticketSeller.ten + "张," + "20元面值的钞票" + ticketSeller.twenty + "张");
	}

}

运行结果可能有2种情况,如下:

情况1

情况2

标签:java,20,钞票,println,线程,面值,ticketSeller,中线,售票员
来源: https://blog.csdn.net/czh500/article/details/88921086