Java基础学习生疏知识点总结(19)——多线程(下)
2021/4/23 1:55:08
本文主要是介绍Java基础学习生疏知识点总结(19)——多线程(下),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
文章目录
- 1、线程生命周期
- 2、多线程的实现方式二:Runnable
- 3、继承Thread(方式一)和实现Runnable接口(方式二)比较
- 4、数据安全问题
1、线程生命周期
五种线程状态
新建:线程对象刚刚创建出来 没有start
就绪:执行start方法 启动了 没有CPU的执行权
执行:抢到了CPU的执行权 该线程在CPU上运行
阻塞:没有CPU的执行权 还缺少一些必要条件
死亡:线程中的run方法执行完,被当做垃圾被垃圾回收机制回收
各个状态之间的转换
2、多线程的实现方式二:Runnable
步骤
1.实现Runnable接口
2.重写run方法
3.创建Runnable子类对象
4.创建Thread对象,并且把刚创建的Runnable子类对象作为参数传递
5.start方法启动
public class Demo { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); // thread 对象才代表线程 Thread thread = new Thread(myRunnable); thread.setName("宋仲基"); thread.start(); } } class MyRunnable implements Runnable { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() +"---"+i); } } }
注意事项
-
我们Runnable接口子类的run()方法代码,会运行在子线程当中。
-
所以,在线程的第二种实现方式中,我们自己定义子类,实现Runnable接口的run方法,将要在子线程中执行
-
但是,Runnable子类对象,并不代表线程,它只代表,要在线程中执行的任务。
我们认为,从逻辑上说,第二种方法逻辑十分清晰:
-
线程就是一条执行路径,至于在线程这条执行路径上,究竟执行的是什么样的具体代码, 应该和线程本身没有关系的
-
也就是说,线程,和在线程(执行路径)上执行的任务应该是没有什么直接关系的
-
线程实现的第二种方式,把线程(Thread对象代表线程) 和在 线程上执行的任务(Ruannable子类对象)分开
// 为什么Runnable当中的run方法会运行在子线程当中 new Thread(Runnable target) Thread{ private Runnable target; init(xxx){ this.target = target; } run (){ if(target!=null){ target.run(); } } }
3、继承Thread(方式一)和实现Runnable接口(方式二)比较
方式二一 VS 方式二:
- 方式一实现步骤较方式二少
- 方式一的实现方式,存在单重继承的局限性
- 方式二将线程和任务解耦
- 方式二,便于多线程数据的共享
4、数据安全问题
练习:
多线程仿真如下场景:
假设A电影院正在上映某电影,该电影有100张电影票可供出售,现在假设有3个窗口售票。请设计程序模拟窗口售票的场景。
分析:
3个窗口售票,互不影响,同时进行。
3个窗口共同出售这100张电影票
结果:
- 产生了重复的票
- 产生了不存在的票
方式一:
public class Demo3 { public static void main(String[] args) { SellWindow sellWindow = new SellWindow(); SellWindow sellWindow2 = new SellWindow(); SellWindow sellWindow3 = new SellWindow(); sellWindow.setName("A窗口"); sellWindow2.setName("B窗口"); sellWindow3.setName("C窗口"); sellWindow.start(); sellWindow2.start(); sellWindow3.start(); } } class SellWindow extends Thread { static int tickets = 100; @Override public void run() { while (true) { if (tickets > 0) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName()+"卖了第"+tickets--+"票"); } } } }
方式二:
public class Demo4 { public static void main(String[] args) { SellWindow2 sellWindow2 = new SellWindow2(); Thread thread = new Thread(sellWindow2); Thread thread2 = new Thread(sellWindow2); Thread thread3 = new Thread(sellWindow2); thread.setName("窗口A"); thread2.setName("窗口B"); thread3.setName("窗口C"); thread.start(); thread2.start(); thread3.start(); } } class SellWindow2 implements Runnable { int tickets = 100; @Override public void run() { while (true) { // 假设是线程A抢到CPU的执行权 tickets=100 // 线程B抢到了CPU的执行权 100 // 不存在的原因 假设A执行 此时 tickets=1 if (tickets > 0) { try { // 线程A睡眠 B睡眠 Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +"卖了第"+tickets-- + "票"); // A走到这里 100 // 又发生了线程切换 B抢到了CPU的执行权 100 // A输出 卖了第100 张票 // B输出 卖了第100 张票 // tickets--拆成3步 // 1.取值 2.做-1操作 3.重写赋值 // ABC三个线程都进入了if // 最坏情况 // A 卖了第1张票 此时还剩0张 // B 卖了第0张票 此时还剩-1张票 // C 卖了第-1张票 此时还剩-2张票 } } } }
这篇关于Java基础学习生疏知识点总结(19)——多线程(下)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-26Mybatis官方生成器资料详解与应用教程
- 2024-11-26Mybatis一级缓存资料详解与实战教程
- 2024-11-26Mybatis一级缓存资料详解:新手快速入门
- 2024-11-26SpringBoot3+JDK17搭建后端资料详尽教程
- 2024-11-26Springboot单体架构搭建资料:新手入门教程
- 2024-11-26Springboot单体架构搭建资料详解与实战教程
- 2024-11-26Springboot框架资料:新手入门教程
- 2024-11-26Springboot企业级开发资料入门教程
- 2024-11-26SpringBoot企业级开发资料详解与实战教程
- 2024-11-26Springboot微服务资料:新手入门全攻略