[Java] 线程和可运行接口
第一步,假设有一个票务销售程序。
创建我的线程
从主函数启动
以下是一个样本。
class Mythread extends Thread {
private int ticket = 5;
@Override
public void run() {
for(int i =0 ; i<10 ; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
if(ticket > 0 ) {
ticket--;
L.d("残チケット枚数は"+ticket+"枚");
}
}
}
}
public class ThreadSample {
public static void main(String[] args) {
Mythread mythread = new Mythread();
L.d("チケット販売開始");
mythread.start();
}
}
结果:
ThreadSample#main:34线程名称:主线程id:1 gentest ::开始售票
Mythread#run:24线程名称:Thread-0线程id:11 gentest ::剩余票数为4张
Mythread#run:24线程名称:Thread-0线程id:11 gentest ::剩余票数为3张
Mythread#run:24线程名称:Thread-0线程id:11 gentest ::剩余票数为2张
Mythread#run:24线程名称:Thread-0线程id:11 gentest ::剩余票数为1张
Mythread#run:24线程名称:Thread-0线程id:11 gentest ::剩余票数为0张
第二步,添加在票务销售完成后的报告(回调)。
创建2.1接口
2.2在主要的类(Main Class)中实现接口。
2.3 添加Mythread的构造函数
2.4 给Mythread的run添加回调
以下是一个样本 shì
interface MyTaskResult {
void ticketSoldout();
void ticketRemain();
}
class Mythread extends Thread {
private MyTaskResult myTaskResult;
public Mythread (MyTaskResult myTaskResult) {
this.myTaskResult = myTaskResult;
}
private int ticket = 5;
@Override
public void run() {
for(int i =0 ; i<10 ; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
if(ticket > 0 ) {
ticket--;
L.d("残チケット枚数は"+ticket+"枚");
}
}
if(ticket>0) {
myTaskResult.ticketRemain();
}else {
myTaskResult.ticketSoldout();
}
}
}
public class ThreadSample {
public static void main(String[] args) {
Mythread mythread = new Mythread(myTaskResult);
L.d("チケット販売開始");
mythread.start();
}
static MyTaskResult myTaskResult = new MyTaskResult() {
@Override
public void ticketSoldout() {
L.d("お疲れ様です。");
}
@Override
public void ticketRemain() {
L.d("終わっていないの?");
}
};
}
The result is… (请刷新)
ThreadSample#main:43 线程名称:主线程 线程ID:1 gentest ::开始售票
Mythread#run:28 线程名称:线程-0 线程ID:11 gentest ::剩余票数为4张
Mythread#run:28 线程名称:线程-0 线程ID:11 gentest ::剩余票数为3张
Mythread#run:28 线程名称:线程-0 线程ID:11 gentest ::剩余票数为2张
Mythread#run:28 线程名称:线程-0 线程ID:11 gentest ::剩余票数为1张
Mythread#run:28 线程名称:线程-0 线程ID:11 gentest ::剩余票数为0张
ThreadSample$1#ticketSoldout:50 线程名称:线程-0 线程ID:11 gentest ::辛苦了。
第三步,使用多台自动售票机销售门票。
3.1 添加可执行的(TicketBox)
增加Thread数量,增加Thread名称(代理1,2,3)
下面是一个示例。
interface MyTaskResult {
void ticketSoldout(String threadName);
void ticketRemain(String threadName);
}
class TicketBox implements Runnable {
private int ticket = 5;
@Override
public void run() {
for(int i =0 ; i<10 ; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
if(ticket > 0 ) {
ticket--;
L.d("残チケット枚数は"+ticket+"枚");
}
}
L.d("完了 チケット:"+ticket);
}
}
class Mythread extends Thread {
private MyTaskResult myTaskResult;
public Mythread (Runnable r, MyTaskResult myTaskResult,String threadName) {
super(r);
this.myTaskResult = myTaskResult;
setName(threadName);
}
private int ticket = 5;
@Override
public void run() {
super.run();
}
}
public class ThreadSample {
public static void main(String[] args) {
TicketBox ticketBox = new TicketBox();
Mythread mythread1 = new Mythread(ticketBox,myTaskResult,"代理1");
Mythread mythread2 = new Mythread(ticketBox,myTaskResult,"代理2");
Mythread mythread3 = new Mythread(ticketBox,myTaskResult,"代理3");
L.d("チケット販売開始");
mythread1.start();
mythread2.start();
mythread3.start();
}
static MyTaskResult myTaskResult = new MyTaskResult() {
@Override
public void ticketSoldout(String threadName) {
L.d("お疲れ様です。"+threadName);
}
@Override
public void ticketRemain(String threadName) {
L.d("終わっていないの?"+threadName);
}
};
}
结果 –
ThreadSample#main:52线程名称:main线程ID:1 gentest ::门票销售开始
TicketBox#run:23线程名称:代理2线程ID:12 gentest ::剩余门票数为3张
TicketBox#run:23线程名称:代理1线程ID:11 gentest ::剩余门票数为3张
TicketBox#run:23线程名称:代理3线程ID:13 gentest ::剩余门票数为3张
TicketBox#run:23线程名称:代理1线程ID:11 gentest ::剩余门票数为2张
TicketBox#run:23线程名称:代理2线程ID:12 gentest ::剩余门票数为1张
TicketBox#run:23线程名称:代理3线程ID:13 gentest ::剩余门票数为0张
TicketBox#run:26线程名称:代理2线程ID:12 gentest ::完成 剩余门票:0
TicketBox#run:26线程名称:代理3线程ID:13 gentest ::完成 剩余门票:0
TicketBox#run:26线程名称:代理1线程ID:11 gentest ::完成 剩余门票:0
问题点:
1、5张票卖出了6次。(需要同步处理)
2、每个代理商都没有统计出售了多少张票。
第四步 同步处理
class TicketBox implements Runnable {
private int ticket = 5;
@Override
public void run() {
for(int i =0 ; i<10 ; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
saleTicket();
}
L.d("完了 残チケット:"+ticket);
}
private synchronized void saleTicket() {
if(ticket > 0 ) {
ticket--;
L.d("残チケット枚数は"+ticket+"枚");
}
}
}
结果
线程示例#main:55 线程名称:主线程 线程ID:1 gentest ::开始售票
票箱#售票:28 线程名称:代理2 线程ID:12 gentest ::剩余票数为4张
票箱#售票:28 线程名称:代理3 线程ID:13 gentest ::剩余票数为3张
票箱#售票:28 线程名称:代理1 线程ID:11 gentest ::剩余票数为2张
票箱#售票:28 线程名称:代理2 线程ID:12 gentest ::剩余票数为1张
票箱#售票:28 线程名称:代理1 线程ID:11 gentest ::剩余票数为0张
票箱#运行:23 线程名称:代理2 线程ID:12 gentest ::完成,剩余票数:0
票箱#运行:23 线程名称:代理3 线程ID:13 gentest ::完成,剩余票数:0
票箱#运行:23 线程名称:代理1 线程ID:11 gentest ::完成,剩余票数:0
步骤五:销售结果总结。
请参考GitHub。
结果 (jié guǒ)
ThreadSample#main:85 线程名:main 线程ID:1 代理销售测试::开始售票
TicketBox#saleTicket:52 线程名:代理2 线程ID:12 代理销售测试::剩余票数为4张
TicketBox#saleTicket:52 线程名:代理1 线程ID:11 代理销售测试::剩余票数为3张
TicketBox#saleTicket:52 线程名:代理3 线程ID:13 代理销售测试::剩余票数为2张
TicketBox#saleTicket:52 线程名:代理1 线程ID:11 代理销售测试::剩余票数为1张
TicketBox#saleTicket:52 线程名:代理2 线程ID:12 代理销售测试::剩余票数为0张
ThreadSample$1#taskDone:95 线程名:代理1 线程ID:11 代理销售测试::辛苦了,代理1
ThreadSample$1#taskDone:95 线程名:代理2 线程ID:12 代理销售测试::辛苦了,代理2
ThreadSample$1#taskDone:95 线程名:代理3 线程ID:13 代理销售测试::辛苦了,代理3
ThreadSample$1#taskDone:100 线程名:代理3 线程ID:13 代理销售测试::—————-全部完成报告—————————-
ThreadSample$2#sendResult:108 线程名:代理3 线程ID:13 代理销售测试::总票数为:5
ThreadSample$2#sendResult:109 线程名:代理3 线程ID:13 代理销售测试::剩余票数为:0
ThreadSample$2#sendResult:110 线程名:代理3 线程ID:13 代理销售测试::代理1销售结果:2
ThreadSample$2#sendResult:111 线程名:代理3 线程ID:13 代理销售测试::代理2销售结果:2
ThreadSample$2#sendResult:112 线程名:代理3 线程ID:13 代理销售测试::代理3销售结果:1