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