Java创建多线程的两种基本方法:

方法1.继承Thread类
(1)定义子类,继承Thread类,重写该类的run()方法作为线程执行体;
(2)创建该子类的实例作为线程对象;

(3)调用线程对象的start()方法来启动线程;

我们以模拟火车售票系统为例:

public class SellTicket {public static void main(String[] args) {for(int i=1; i<4; i++){TicketWindow tw = new TicketWindow();tw.setName("TicketWindow-" + i);tw.start();}}
}class TicketWindow extends Thread{private int tickets = 100;//车票总量@Overridepublic void run(){while(true){if(tickets>0){System.out.println(Thread.currentThread().getName() + "准备出票,剩余票数:" + tickets + "张");                    tickets--;                                                                                              System.out.println(Thread.currentThread().getName() + "卖出一张,剩余票数:" + tickets + "张");try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}else{System.out.println(Thread.currentThread().getName() + "余票不足,停止售票!");break;}}}
}

方法2.实现Runnable接口

(1)定义类实现Runnable接口,重写run()方法;
(2)创建该实现类的实例,以该实例作为Thread的target来创建Thread对象;

(3)调用该Thread对象的start()方法来启动该线程;

还是以模拟火车售票窗口为例:

public class SellTicket {public static void main(String[] args) {TicketWindow tw = new TicketWindow();for(int i=1; i<4; i++){Thread t = new Thread(tw,"TickWindow-" + i);t.start();}}
}class TicketWindow implements Runnable{private int tickets = 100;//车票总量@Overridepublic void run(){while(true){if(tickets>0){System.out.println(Thread.currentThread().getName() + "准备出票,剩余票数:" + tickets + "张");                    tickets--;                                                                                              System.out.println(Thread.currentThread().getName() + "卖出一张,剩余票数:" + tickets + "张");try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}else{System.out.println(Thread.currentThread().getName() + "余票不足,停止售票!");break;}}}
}

注意:

继承Thread类与实现Runnable接口的区别及优缺点对比:

  继承Thread类 实现Runnable接口
能否继承其他类 不能
如何访问当前线程 this即为当前线程 Thread.currentThread()
是否共享同一target 是,适合多个相同线程处理同一份资源的情况

因此,一般推荐采用实现Runnable接口/Callable接口的方式创建多线程;

虽然上面实现Runnable接口的火车售票系统共享了车票总数,但是没有控制同一时刻只能有一个线程进行卖票操作,因此需要同步关键字 synchronized 进行控制,

线程同步分为同步块和同步方法:

1.同步块

同步块的语法格式为:

synchronized(object){//...同步代码块
}

上述代码的意思是,要想执行同步代码块,必须先获得同步监视器的锁定.

其中object为同步监视器,一般使用可能被并发访问的共享资源当同步监视器;

下面给出java多线程模拟火车售票系统的同步块实现:

 public static void main(String[] args) {TicketWindow tw = new TicketWindow();for(int i=1; i<4; i++){Thread t = new Thread(tw,"TickWindow-" + i);t.start();}}
}class TicketWindow implements Runnable{private int tickets = 10;//车票总量@Overridepublic void run(){while(true){synchronized (this) {if(tickets>0){System.out.println(Thread.currentThread().getName() + "准备出票,剩余票数:" + tickets + "张");                    tickets--;                                                                                              System.out.println(Thread.currentThread().getName() + "卖出一张,剩余票数:" + tickets + "张");try {//休眠100ms卖票完会报错ERROR: JDWP Unable to get JNI 1.2 environment, jvm->GetEnv() return code = -2JDWP exit error AGENT_ERROR_NO_JNI_ENV(183):  [../../../src/share/back/util.c:820]//Thread.sleep(100);Thread.sleep(500);//出票成功后让当前售票窗口睡眠,以便让其他售票窗口卖票} catch (InterruptedException e) {e.printStackTrace();}}else{System.out.println(Thread.currentThread().getName() + "余票不足,停止售票!");break;}}}}
}

输出:

TickWindow-1准备出票,剩余票数:10张
TickWindow-1卖出一张,剩余票数:9张
TickWindow-1准备出票,剩余票数:9张
TickWindow-1卖出一张,剩余票数:8张
TickWindow-1准备出票,剩余票数:8张
TickWindow-1卖出一张,剩余票数:7张
TickWindow-1准备出票,剩余票数:7张
TickWindow-1卖出一张,剩余票数:6张
TickWindow-1准备出票,剩余票数:6张
TickWindow-1卖出一张,剩余票数:5张
TickWindow-1准备出票,剩余票数:5张
TickWindow-1卖出一张,剩余票数:4张
TickWindow-1准备出票,剩余票数:4张
TickWindow-1卖出一张,剩余票数:3张
TickWindow-1准备出票,剩余票数:3张
TickWindow-1卖出一张,剩余票数:2张
TickWindow-3准备出票,剩余票数:2张
TickWindow-3卖出一张,剩余票数:1张
TickWindow-3准备出票,剩余票数:1张
TickWindow-3卖出一张,剩余票数:0张
TickWindow-3余票不足,停止售票!
TickWindow-2余票不足,停止售票!
TickWindow-1余票不足,停止售票!

2.同步方法.

同步方法就是使用 synchronized 关键字修饰某个方法,synchronized 修饰的实例方法(非static方法)的同步监视器是this.

使用同步方法解决共享资源的多线程访问冲突的一般方式是:

        //把修改共享资源的方法使用synchronized进行修饰public synchronized void someMethod(){//do something...}//在run()方法中调用该同步方法public void run(){someMethod();}

下面给出使用同步方法实现的模拟火车售票系统:

public class SellTicket {public static void main(String[] args) {TicketWindow tw = new TicketWindow();for(int i=1; i<4; i++){Thread t = new Thread(tw,"TickWindow-" + i);t.start();}}
}class TicketWindow implements Runnable{private int tickets = 10;//车票总量@Overridepublic void run(){while(true){sellTicket();}}public synchronized void sellTicket(){if(tickets>0){System.out.println(Thread.currentThread().getName() + "准备出票,剩余票数:" + tickets + "张");                    tickets--;                                                                                              System.out.println(Thread.currentThread().getName() + "卖出一张,剩余票数:" + tickets + "张");try {Thread.sleep(500);//出票成功后让当前售票窗口睡眠,以便让其他售票窗口卖票} catch (InterruptedException e) {e.printStackTrace();}}else{System.out.println(Thread.currentThread().getName() + "余票不足,停止售票!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}

输出:

TickWindow-1准备出票,剩余票数:10张
TickWindow-1卖出一张,剩余票数:9张
TickWindow-1准备出票,剩余票数:9张
TickWindow-1卖出一张,剩余票数:8张
TickWindow-1准备出票,剩余票数:8张
TickWindow-1卖出一张,剩余票数:7张
TickWindow-1准备出票,剩余票数:7张
TickWindow-1卖出一张,剩余票数:6张
TickWindow-1准备出票,剩余票数:6张
TickWindow-1卖出一张,剩余票数:5张
TickWindow-1准备出票,剩余票数:5张
TickWindow-1卖出一张,剩余票数:4张
TickWindow-1准备出票,剩余票数:4张
TickWindow-1卖出一张,剩余票数:3张
TickWindow-1准备出票,剩余票数:3张
TickWindow-1卖出一张,剩余票数:2张
TickWindow-1准备出票,剩余票数:2张
TickWindow-1卖出一张,剩余票数:1张
TickWindow-1准备出票,剩余票数:1张
TickWindow-1卖出一张,剩余票数:0张
TickWindow-1余票不足,停止售票!
TickWindow-1余票不足,停止售票!
TickWindow-1余票不足,停止售票!
TickWindow-1余票不足,停止售票!
TickWindow-1余票不足,停止售票!
TickWindow-3余票不足,停止售票!
TickWindow-2余票不足,停止售票!
TickWindow-3余票不足,停止售票!
TickWindow-3余票不足,停止售票!

注意:while(true){}要放在run()方法里面,而不是sell方法里. 否则会出现某一个窗口一直把票卖完的情况.

要想让售票窗口在售完票之后停止,需要在run()方法里的作条件限制,修改如下:

public class SellTicket {public static void main(String[] args) {TicketWindow tw = new TicketWindow();for(int i=1; i<4; i++){Thread t = new Thread(tw,"TickWindow-" + i);t.start();}}
}class TicketWindow implements Runnable{private int tickets = 10;//车票总量@Overridepublic void run(){while(true){if(tickets>0){sellTicket();}else{System.out.println(Thread.currentThread().getName() + "余票不足,停止售票!");break;}}}public synchronized void sellTicket(){if(tickets>0){System.out.println(Thread.currentThread().getName() + "准备出票,剩余票数:" + tickets + "张");                    tickets--;                                                                                              System.out.println(Thread.currentThread().getName() + "卖出一张,剩余票数:" + tickets + "张");try {Thread.sleep(500);//出票成功后让当前售票窗口睡眠,以便让其他售票窗口卖票} catch (InterruptedException e) {e.printStackTrace();}}}
}

输出如下:

TickWindow-1准备出票,剩余票数:10张
TickWindow-1卖出一张,剩余票数:9张
TickWindow-1准备出票,剩余票数:9张
TickWindow-1卖出一张,剩余票数:8张
TickWindow-1准备出票,剩余票数:8张
TickWindow-1卖出一张,剩余票数:7张
TickWindow-1准备出票,剩余票数:7张
TickWindow-1卖出一张,剩余票数:6张
TickWindow-1准备出票,剩余票数:6张
TickWindow-1卖出一张,剩余票数:5张
TickWindow-1准备出票,剩余票数:5张
TickWindow-1卖出一张,剩余票数:4张
TickWindow-1准备出票,剩余票数:4张
TickWindow-1卖出一张,剩余票数:3张
TickWindow-1准备出票,剩余票数:3张
TickWindow-1卖出一张,剩余票数:2张
TickWindow-1准备出票,剩余票数:2张
TickWindow-1卖出一张,剩余票数:1张
TickWindow-1准备出票,剩余票数:1张
TickWindow-1卖出一张,剩余票数:0张
TickWindow-1余票不足,停止售票!
TickWindow-3余票不足,停止售票!
TickWindow-2余票不足,停止售票!

注意!

使用 synchronized 修饰run()方法是无效的:

public class SellTicket {public static void main(String[] args) {TicketWindow tw = new TicketWindow();for(int i=1; i<4; i++){Thread t = new Thread(tw,"TickWindow-" + i);t.start();}}
}class TicketWindow implements Runnable{private int tickets = 10;//车票总量@Overridepublic synchronized void run(){while(true){if(tickets>0){System.out.println(Thread.currentThread().getName() + "准备出票,剩余票数:" + tickets + "张");                    tickets--;                                                                                              System.out.println(Thread.currentThread().getName() + "卖出一张,剩余票数:" + tickets + "张");try {Thread.sleep(500);//出票成功后让当前售票窗口睡眠,以便让其他售票窗口卖票} catch (InterruptedException e) {e.printStackTrace();}}else{System.out.println(Thread.currentThread().getName() + "余票不足,停止售票!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}
}

会输出:

TickWindow-1准备出票,剩余票数:10张
TickWindow-1卖出一张,剩余票数:9张
TickWindow-1准备出票,剩余票数:9张
TickWindow-1卖出一张,剩余票数:8张
TickWindow-1准备出票,剩余票数:8张
TickWindow-1卖出一张,剩余票数:7张
TickWindow-1准备出票,剩余票数:7张
TickWindow-1卖出一张,剩余票数:6张
TickWindow-1准备出票,剩余票数:6张
TickWindow-1卖出一张,剩余票数:5张
TickWindow-1准备出票,剩余票数:5张
TickWindow-1卖出一张,剩余票数:4张
TickWindow-1准备出票,剩余票数:4张
TickWindow-1卖出一张,剩余票数:3张
TickWindow-1准备出票,剩余票数:3张
TickWindow-1卖出一张,剩余票数:2张
TickWindow-1准备出票,剩余票数:2张
TickWindow-1卖出一张,剩余票数:1张
TickWindow-1准备出票,剩余票数:1张
TickWindow-1卖出一张,剩余票数:0张
TickWindow-1余票不足,停止售票!
TickWindow-1余票不足,停止售票!
TickWindow-1余票不足,停止售票!
TickWindow-1余票不足,停止售票!

原因见:

https://stackoverflow.com/questions/7313657/should-you-synchronize-the-run-method-why-or-why-not

参考:

https://blog.csdn.net/tomcat_2014/article/details/60575942

Java多线程模拟售票系统相关推荐

  1. 利用JAVA多线程模拟售票系统,对统一资源进行处理

    首先多线程处理统一资源的方式有两种 分别介绍一下两者的区别 synchronized与Lock的区别 1.Lock不是Java语言内置的,synchronized是Java语言的关键字 2.synch ...

  2. Java多线程 模拟售票窗口售票

    编写一个Java 多线程程序,完成三个售票窗口同时出售20张票 程序分析: 1.票数要使用同一个静态值: 2.为保证不会出现卖出同一个票数,要java多线程同步锁. 设计思路: 创建一个站台类Stat ...

  3. Java多线程实现售票系统

    学习多线程比较经典的案例就是实现售票系统了. 我们先来看看需求:铁道部发布了一个售票任务,要求销售100张票,要求有5个窗口来进行销售,效果如下: 窗口001正在销售第100张票窗口001正在销售第9 ...

  4. Java——多线程(铁路售票系统案例)

    问题:铁路售票,一共100张,通过四个窗口卖完. 要求:分别用 继承Thread类 和 实现Runnable接口 去实现 ①用继承Thread类去实现 package com.yy.syn;publi ...

  5. java多线程模拟售票

    售票类: package duoxiancheng;import java.util.concurrent.TimeUnit;/*** @author yeqv* @program A2* @Clas ...

  6. java 模拟火车站售票系统_模拟售票系统java编程

    模拟售票系统java编程 /* 项目:用多线程设计一个模拟火车站售票大厅的工作情形. 问题描述:火车站有许多售票窗口,有些开放,有些不开放.顾客进入火车站售票厅后,到某个售票窗口排队等候,排到了就办理 ...

  7. Java模拟售票窗口代码_java多线程模拟售票,多个窗口售票

    package com.ma.thread001; /** * 多线程模拟售票,多个窗口售票 * @author ma * */ public class SellTicktDemo implemen ...

  8. java多线程模拟购买火车票

    java多线程模拟购买火车票 本次做的是一个火车票的售卖模拟,不管用户是在窗口还是APP上购买,必然不可能买到同一张票这也就是说一张票的售卖必然是一个线程在操作的,所以,我们在写代码是也要注意这一点 ...

  9. 基于JAVA网上汽车售票系统计算机毕业设计源码+数据库+lw文档+系统+部署

    基于JAVA网上汽车售票系统计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVA网上汽车售票系统计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目架构:B/S架构 开发语 ...

最新文章

  1. opencv隔点采样(下采样)
  2. 关于对 linux系统的物理内存访问 /dev/mem
  3. linux运行geoserver源码,Linux 下Geoserver 的部署
  4. 广东移动节能绿色数据中心掀起“能耗革命”
  5. 利用一维数组求菲波那契数列前40项的和并输出结果。_[W2D2]斐波那契数列
  6. SpringBoot Environment读取配置文件乱码
  7. 中缀表达式——表达式树
  8. Java8实战(Java8 in Action)精华篇
  9. ZUC算法的Python实现
  10. 格雷希尔Gripseal燃油管快速接头如何做密封性测试
  11. 如何计算802.11 PHY Data Rate (11ac/11ax)
  12. 跨境电商适合做独立站吗,是入平台好还是独立站好?
  13. 防止恶意刷新页面的Java实现
  14. 抽象数据类型 C++实现 计算复数 [(8+6i)*(4+3i)]/[(8+6i)+(4+3i)]= ?
  15. 火焰图片和视频数据集
  16. 2021年红包封面小程序源码独立后台无限裂变线上线下引流工具微信流量主小程序
  17. [luogu1710]地铁涨价(bfs)
  18. python编程入门课 视频-为了学习Python,我汇总了这10个免费的视频课程!
  19. Leon2微处理器IP核原理及应用
  20. 新基建下区块链基础设施建设

热门文章

  1. 位运算 之(1) 按位与(AND) 操作
  2. 虚拟机网卡起不来,配置文件中的IP地址无法加载到网卡(Bringing up interface ens33: Error: Connection activation failed: No sui)
  3. 前端Vue入门-day04-用vue实现组件通信
  4. 零基础java自学流程-Java语言高级534
  5. 传言阿里P10赵海平被P11多隆判定3.25离职,如何评价阿里 P10 赵海平对王垠的面试?...
  6. 视频中IBP帧的介绍和判定方法
  7. Bray-Curtis相异矩阵系数
  8. 怎么检测两张照片的相似度,两张图片相似度测试
  9. 联翔股份——2022年5月10日申购
  10. python矩阵的基本运算