java中多线程编程_JAVA多线程编程实例

1.三个售票窗口同时出售20张票

程序分析: (1)票数要使用同一个静态值 (2)为保证不会出现卖出同一个票数,要 java 多线程同步锁。 设计思路: (1)创建一个站台类Station,继承 Thread,重写 run方法,在 run 方法里面执行售票操作!售票要使用同步锁:即有一个站台卖这张票时,其他站台要等这张票卖完! (2)创建主方法调用类

(一)创建一个站台类,继承 Threadpackage com.xykj.threadStation;

public class Station extends Thread {

// 通过构造方法给线程名字赋值

public Station(String name) {

super(name);// 给线程名字赋值

}

// 为了保持票数的一致,票数要静态

static int tick = 20;

// 创建一个静态钥匙

static Object ob = "aa";//值是任意的

// 重写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 com.xykj.threadStation;

public class MainClass {

/**

* java多线程同步锁的使用

* 示例:三个售票窗口同时出售10张票

* */

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();

}

}

程序运行结果:窗口1卖出了第20张票

窗口2卖出了第19张票

窗口3卖出了第18张票

窗口3卖出了第17张票

窗口1卖出了第16张票

窗口2卖出了第15张票

窗口3卖出了第14张票

窗口1卖出了第13张票

窗口2卖出了第12张票

窗口2卖出了第11张票

窗口1卖出了第10张票

窗口3卖出了第9张票

窗口3卖出了第8张票

窗口1卖出了第7张票

窗口2卖出了第6张票

窗口3卖出了第5张票

窗口1卖出了第4张票

窗口2卖出了第3张票

窗口3卖出了第2张票

窗口1卖出了第1张票

票卖完了

可以看到票数是不会有错的!

2.两个人AB通过一个账户A在柜台取钱和B在ATM机取钱!

程序分析:

钱的数量要设置成一个静态的变量,两个人要取的同一个对象值。 (一)创建一个 Bank 类package com.thread.demo.demo2;

import java.util.Objects;

public class Bank {

// 假设一个账户有1000块钱

static double money = 1000;

// 柜台Counter取钱的方法

private void Counter(double money) {

Bank.money -= money;

System.out.println("柜台取钱" + money + "元,还剩" + Bank.money + "元!");

}

// ATM取钱的方法

private void ATM(double money) {

Bank.money -= money;

System.out.println("ATM取钱" + money + "元,还剩" + Bank.money + "元!");

}

//提供一个对外取款途径,防止直接调取方法同时取款时,并发余额显示错误

public synchronized void outMoney(double money, String mode) throws Exception{

if(money > Bank.money){

//校验余额是否充足

throw new Exception("取款金额"+money+",余额只剩"+Bank.money+",取款失败");

}

if(Objects.equals(mode, "ATM")){

ATM(money);

} else {

Counter(money);

}

}

}

(二)创建一个 PersonA 类package com.thread.demo.demo2;

public class PersonA extends Thread {

Bank bank;

String mode;

public PersonA(Bank bank, String mode) {

this.mode = mode;

this.bank = bank;

}

while(bank.money >= 100){

try {

bank.outMoney(100, mode);

} catch (Exception e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

try {

sleep(100);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

(三)创建一个 PersonB 类package com.thread.demo.demo2;

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 >= 200) {

try {

bank.outMoney(200, mode);

} catch (Exception e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

try {

sleep(100);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

(四)创建主方法的调用类package com.thread.demo.demo2;

/**

* 两个人AB通过一个账户A在柜台取钱和B在ATM机取钱

* */

public class MainClass {

public static void main(String[] args) {

Bank bank = new Bank();

// 实例化两个人,传入同一个银行的对象

PersonA a = new PersonA(bank, "Counter");

PersonB b = new PersonB(bank, "ATM");

a.start();

b.start();

}

}

运行结果:

4b935392354896a5ca4dbdc26e9a3ec1.png

可以看到取完就停止运行了。

3.龟兔赛跑问题

龟兔赛跑: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个要求涉及到线程回调。需要在动物类创建一个回调接口,创建一个回调对象。

(一)创建 Animal 动物类package com.thread.demo.demo3;

public abstract class Animal extends Thread {

public int length = 2000;// 比赛长度

public abstract void runing();

@Override

public void run() {

super.run();

while (length > 0) {

runing();

}

}

// 在需要回调数据的地方(两个子类需要),声明一个接口

public static interface Calltoback {

public void win();

}

// 2.创建接口对象

public Calltoback calltoback;

}

(二)创建 Rabbit 兔子类package com.thread.demo.demo3;

public class Rabbit extends Animal {

public Rabbit() {

setName("兔子");

}

@Override

public void runing() {

//兔子速度

int dis = 5;

length -= dis;

System.out.println("兔子跑了" + dis + "米,距离终点还有" + 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 { //没0.1秒跑5米

sleep(100);

}

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

(三)创建 Tortoise 乌龟类package com.thread.demo.demo3;

public class Tortoise extends Animal {

public Tortoise() {

setName("乌龟");// Thread的方法,给线程赋值名字

}

// 重写running方法,编写乌龟的奔跑操作

@Override

public void runing() {

// 乌龟速度

int dis = 2;

length -= dis;

System.out.println("乌龟跑了" + dis + "米,距离终点还有" + 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 com.thread.demo.demo3;

import com.thread.demo.demo3.Animal.Calltoback;

public class LetOneStop implements Calltoback {

// 动物对象

Animal an;

// 获取动物对象,可以传入兔子或乌龟的实例

public LetOneStop(Animal an) {

this.an = an;

}

// 让动物的线程停止

@Override

public void win() {

// 线程停止

an.stop();

}

}

(五)创建一个主方法调用类package com.thread.demo.demo3;

public class MainClass {

/**

* 龟兔赛跑:2000米

*/

public static void main(String[] args) {

// 实例化乌龟和兔子

Tortoise tortoise = new Tortoise();

Rabbit rabbit = new Rabbit();

// 回调方法的使用,谁先调用calltoback方法,另一个就不跑了

LetOneStop letOneStop1 = new LetOneStop(tortoise);

// 让兔子的回调方法里面存在乌龟对象的值,可以把乌龟stop

rabbit.calltoback = letOneStop1;

LetOneStop letOneStop2 = new LetOneStop(rabbit);

// 让乌龟的回调方法里面存在兔子对象的值,可以把兔子stop

tortoise.calltoback = letOneStop2;

// 开始跑

tortoise.start();

rabbit.start();

}

}

运行结果:

d5b9c825ccc3fc1747cc543aa15d9c00.png

4. 线程示例总结

(1)代码块锁是一个防止数据发生错误的一个重要手段;

(2)对象的统一性是非常重要的,这要想到对象的传入问题,要操作的对象只能new一次,其他的操作都是对这个传入的对象进行的,才能保证数据一致性,完整性和正确性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值