三个售票窗口同时出售20张票
** (1)票数要使用同一个静态值
(2)为保证不会出现卖出同一个票数,要java多线程同步锁。
设计思路:
(1)创建一个站台类Station,继承Thread,重写run方法,在run方法里面执行售票操作!售票要使用同步锁:即有一个站台卖这张票时,其他站台要等这张票卖完!
(2)创建主方法调用类
站台类:
package java_multi_thread.sell_ticket_example;
/**
* Created by hasee
* on 2019/12/12 20:52
* 站台类,继承thread
*/
public class Station extends Thread {
//通过构造方法给线程名字赋值
public Station(String name){
super(name);//为线程名字赋值
}
//为保持票数的一致,票数要静态
public static int tick = 30;
//创建一个静态方法
public static Object ob = 't';//值可以任意
//重写run方法,实现买票操作
@Override
public void run(){
while(tick > 0){
synchronized (ob) {//同步锁
// 进去买票的人会把钥匙拿在手上,出来后才把钥匙拿让出来
if(tick > 0){
System.out.println(getName()+"卖出了"+tick+"张票");
tick --;
}else{
System.out.println("票已售空!");
}
}
try {
sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
执行类:
package java_multi_thread.sell_ticket_example;
/**
* Created by hasee
* on 2019/12/12 21:01
*
* java多线程同步锁的使用
* 三个窗口同时售票
*/
public class MainClass {
public static void main(String[] args){
//实例化站台
Station station1 = new Station("1号窗口");
Station station2 = new Station("2号窗口");
Station station3 = new Station("3号窗口");
//让每一个对象各自开始工作
station1.start();
station2.start();
station3.start();
}
}
两个人AB通过一个账户A在柜台取钱和B在ATM机取钱
钱的数量要设置成一个静态的变量,两个人要取的同一个对象值
银行类:
package java_multi_thread.two_person_user_atm_example;
import java.util.Objects;
/**
* Created by hasee
* on 2019/12/12 21:12
*/
public class Bank {
//设定一个账户余额
public static int money = 3000;
//在柜台取钱
public void counter(double money){
Bank.money -= money;
System.out.println("从柜台取钱--"+"账户余额:"+Bank.money);
}
//在ATM取钱
public void atm(double money){
Bank.money -=money;
System.out.println("从ATM取钱--"+"账户余额"+Bank.money);
}
//提供一个对外取款途径,防止直接调取方法同时取款时,并发余额显示错误
public synchronized void outMoney(double money,String mode) throws Exception{
if(Bank.money < money){
throw new Exception("取款金额:"+money+",您的账户余额:"+Bank.money+",取款失败!");
}
if(Objects.equals(mode,"atm")){
atm(money);
}else{
counter(money);
}
}
}
取钱人A:
package java_multi_thread.two_person_user_atm_example;
/**
* Created by hasee
* on 2019/12/12 21:23
*/
public class PersonA extends Thread{
Bank bank;
String mode;
public PersonA(Bank bank,String mode){
this.bank = bank;
this.mode = mode;
}
public void run(){
while (bank.money >= 100){
try {
bank.outMoney(100,mode);
}catch (Exception e1){
e1.printStackTrace();
}
try {
sleep(1000);
}catch (InterruptedException e2){
e2.printStackTrace();
}
}
}
}
取钱人B:
package java_multi_thread.two_person_user_atm_example;
/**
* Created by hasee
* on 2019/12/12 21:28
*/
public class PersonB extends Thread{
Bank bank;
String mode;
public PersonB(Bank bank,String mode){
this.bank = bank;
this.mode = mode;
}
public void run(){
while (bank.money >= 100){
try {
bank.outMoney(350,mode);
}catch (Exception e1){
e1.printStackTrace();
}
try {
sleep(1000);
}catch (InterruptedException e2){
e2.printStackTrace();
}
}
}
}
执行类:
package java_multi_thread.two_person_user_atm_example;
/**
* Created by hasee
* on 2019/12/12 21:28
*/
public class MainClass {
public static void main(String[] args){
Bank bank = new Bank();
//实例化PersonA、B,传入同一个银行bank
PersonA personA = new PersonA(bank,"atm");
PersonB personB = new PersonB(bank,"counter");
personA.start();
personB.start();
}
}
龟兔赛跑问题
龟兔赛跑:2000米
要求:
(1)兔子每 0.1 秒 5 米的速度,每跑20米休息1秒;
(2)乌龟每 0.1 秒跑 2 米,不休息;
(3)其中一个跑到终点后另一个不跑了!
程序设计思路:
(1)创建一个Animal动物类,继承Thread,编写一个running抽象方法,重写run方法,把running方法在run方法里面调用。
(2)创建Rabbit兔子类和Tortoise乌龟类,继承动物类
(3)两个子类重写running方法
(4)本题的第3个要求涉及到线程回调。需要在动物类创建一个回调接口,创建一个回调对象。
动物类:抽象类(abstract)
package java_multi_thread.animal_race;
/**
* Created by hasee
* on 2019/12/12 21:42
*/
public abstract class Animal extends Thread {
public int length = 500;
public abstract void runing();
@Override
public void run(){
super.run();
while (length > 0){
runing();
}
}
// 在需要回调数据的地方(两个子类需要),声明一个接口
public static interface Calltoback{
public void win();
}
//创建接口对象
public Calltoback calltoback;
}
乌龟类:
package java_multi_thread.animal_race;
/**
* Created by hasee
* on 2019/12/12 21:50
*/
public class Tortoise extends Animal {
public Tortoise(){
setName("Tortoise");
}
@Override
public void runing() {
//乌龟的速度
int speed = 2;
length -= speed;
System.out.println("兔子跑了"+speed+"米,距离终点还有"+length+"米");
if(length <= 0){
length = 0;
System.out.println("乌龟获得胜利");
//给回调对象赋值,让兔子别跑了
if(calltoback != null){
calltoback.win();
}
}
try {
sleep(100);//每0.1秒跑2米
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
兔子类:
package java_multi_thread.animal_race;
/**
* Created by hasee
* on 2019/12/12 21:45
*/
public class Rabbit extends Animal {
public Rabbit(){
setName("Rabbit");
}
@Override
public void runing() {
//兔子的速度
int speed = 5;
length -= speed;
System.out.println("兔子跑了"+speed+"米,距离终点还有"+length+"米");
if(length <= 0){
length = 0;
System.out.println("兔子获得胜利");
//给回调对象赋值,让乌龟别跑了
if(calltoback != null){
calltoback.win();
}
}
try {
if((2000 - length)%20 ==0){// 每20米休息一次,休息时间是1秒
sleep(1000);
}else{
sleep(100);//每0.1秒跑5米
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
静止类:(判断是否已有胜者)
package java_multi_thread.animal_race;
/**
* Created by hasee
* on 2019/12/12 21:52
*/
public class LetOneStop implements Animal.Calltoback {
//动物
Animal animal;
//获取动物对象,可以传入乌龟或者兔子的实例
public LetOneStop(Animal animal){
this.animal = animal;
}
@Override
public void win() {
//让线程停止
animal.stop();
}
}
执行类:
package java_multi_thread.animal_race;
/**
* Created by hasee
* on 2019/12/12 21:52
*/
public class MainClass {
public static void main(String[] args){
//实例化动物
Rabbit rabbit = new Rabbit();
Tortoise tortoise = new Tortoise();
//回调方法的使用,谁先使用calltoback方法,另一个就停下
LetOneStop letOneStop1 = new LetOneStop(tortoise);
// 让兔子的回调方法里面存在乌龟对象的值,可以把乌龟stop
rabbit.calltoback = letOneStop1;
LetOneStop letOneStop2 = new LetOneStop(rabbit);
// 让乌龟的回调方法里面存在兔子对象的值,可以把兔子stop
tortoise.calltoback = letOneStop2;
// 开始跑
tortoise.start();
rabbit.start();
}
}
线程示例总结
(1)代码块锁是一个防止数据发生错误的一个重要手段;
(2)对象的统一性是非常重要的,这要想到对象的传入问题,要操作的对象只能new一次,其他的操作都是对这个传入的对象进行的,才能保证数据一致性,完整性和正确性。