三个售票窗口同时出售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方法,实现买票操作@Overridepublic 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,传入同一个银行bankPersonA 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();@Overridepublic 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");}@Overridepublic 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");}@Overridepublic 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;}@Overridepublic 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);// 让兔子的回调方法里面存在乌龟对象的值,可以把乌龟stoprabbit.calltoback = letOneStop1;LetOneStop letOneStop2 = new LetOneStop(rabbit);// 让乌龟的回调方法里面存在兔子对象的值,可以把兔子stoptortoise.calltoback = letOneStop2;// 开始跑tortoise.start();rabbit.start();}}
线程示例总结
(1)代码块锁是一个防止数据发生错误的一个重要手段;
(2)对象的统一性是非常重要的,这要想到对象的传入问题,要操作的对象只能new一次,其他的操作都是对这个传入的对象进行的,才能保证数据一致性,完整性和正确性。
