五种线程状态
新建:线程对象刚刚创建出来 没有start
就绪:执行start方法 启动了 没有CPU的执行权
执行:抢到了CPU的执行权 该线程在CPU上运行
阻塞:没有CPU的执行权 还缺少一些必要条件
死亡:线程中的run方法执行完,被当做垃圾被垃圾回收机制回收
各个状态之间的转换
步骤
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(); } } }
方式二一 VS 方式二:
练习:
多线程仿真如下场景:
假设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张票 } } } }