多线程这个概念在经过一段时间的开发后,考虑接口等问题的时候很容易考虑到。比如做电商系统中库存抢购,车票购买的时候如何控制等问题,根本原因就在于一个多线程安全问题,本章提出的解决方法时通过同步代码快的方式,将多线程异步问题 改为多线程同步,这样无论下单的是谁,都是经过一笔一笔单子来处理,这样就不会出现多线程等问题.当然也可以通过消息队列等方式来控制,下单的时候都需要排队,或者通过其他方式实现多线程并发 数据安全等问题.这里暂不做讨论,这里来回顾下多线程的一些概念性问题.
进程/线程的介绍 计算机操作系统中 任务管理器管理多个进程,系统将分配给每一个进程一段cpu时间片,一个进程的时间片执行完毕,执行另一个进程的CPU时间片,因为每一个cpu时间片都非常短,所以看起来就像是 同时在执行多个任务一样.有点像动画的似得,本质就是多个图片组成的动画。只不过感觉不出来而已。而线程就是进程中将系统分配的CPU时间片 再次划分,分配到线程的时间片就更短。
创建线程的2种方式
创建的线程类实现Runnable接口,实现接口中的run方法,然后通过创建Thread,通过Thread(Runnable target)的构造方法将 线程类实例化,调用Thread的start方法 将线程由创建状态进入就绪状态. package core.thread; public class ThreadTest2 implements Runnable { int num = 10; public void run() { while (true) { System.out.println(num); if (--num == 0) { return; } } } public static void main(String[] args) { new ThreadTest().start(); } } 创建线程类 继承Thread类,重写其中的run方法。然后 通过继承的Thread类的strart()方法,启动线程。同时这个Thread类 实际上是实现Runnable接口的run方法的. package core.thread; public class ThreadTest extends Thread { int num = 10; public void run() { while (true) { System.out.println(num); if (--num == 0) { return; } } } public static void main(String[] args) { new ThreadTest().start(); } }线程的生命周期 线程从创建到销毁存在7个生命周期.
创建:线程通过继承Thread或实现Runnable的方式创建类,线程就被创建了就绪:线程通start方法 启动线程,线程进入就绪状态,等待CPU时间片分配进入运行状态.运行:线程分配到cpu时间片,开始执行阻塞:线程执行后,等待输入或者输出命令,在此期间为阻塞状态.休眠:线程执行sleep方法,进行休眠状态,休眠时间过去了,重新进入就绪状态.等待:线程执行wait方法,进行线程等待状态.可以ton过notify唤醒线程死亡:线程执行完毕,销毁了。处于死亡状态. 用一张图就这么表示了.线程状态切换的方法
使线程处于就绪状态的方法 start方法/进程输入输出 执行完毕/sleep线程刚休眠结束/wait线程等待完毕
线程由就绪状态 进入运行状态的方法 线程等待调用notify方法线程唤醒/notifyAll唤醒所有的线程(也就是说线程等待完毕 处于就绪状态/如果调用notify时不等待了 直接进入运行状态了 相当于 插队 开挂了)/interrupt线程中断(当一个线程处于就绪状态 直接打断状态)/线程阻塞完毕/线程休眠状态
操作线程的方法
线程休眠 sleep(Long time); 毫秒为单位 Long类型线程加入join(); A线程中的run方法执行join(Thread B)线程,这样就会先执行B线程,然后才执行A线程。类似于插队.线程中断.interrupted()之前有个stop方法 不用了.线程礼让yield。不保证礼让结果。线程优先级 从1到10自小而大 优先级一层层提高. 正常的为NORMAL_PRIORITY.最小的为MIN_PRIORITY.最大的为MAX_PRIORITY.优先级越高,相同时间片段下,优先级高的在前面先执行. 线程同步安全问题 synchornize是控制多线程的最简单的方法,但是仅是在业务量不大的情况下,通过线程同步来防止数据混乱的问题,举个最简单的例子,卖车票在最后一张的时候,如果多个人都下单了,下单之后有一一系列业务数据操作,耗时比较长,虽然可以考虑解耦,但如果网络 性能等问题造成 前一个人下单再判断库存大于0,开始做业务处理 库存-1的操作时,后面一个人也下单 然后库存也大于0 ,开始操作,这样就可能出现库存数量为-1的情况。所以就需要通过synchronzied同步代码块或者同步方法的形式,将多线程通过类似消息队列的方式一次次处理,这样就可以避免线程安全的问题,例子如下.
package core.thread; public class ThreadSafe implements Runnable { int num = 10;// 模拟共享数据 public void run() { while (true) { //利用synchronzied同步代码块的方式 /*synchronized ("") { if (num > 0) { try { Thread.sleep(100); } catch (InterruptedException ex) { ex.printStackTrace(); } System.out.println("tickets:" + num--); } }*/ //利用synchornzied同步方法 doit(); } } private void doit(){ synchronized ("") { if (num > 0) { try { Thread.sleep(100); } catch (InterruptedException ex) { ex.printStackTrace(); } System.out.println("tickets:" + num--); } } } public static void main(String[] args) { ThreadSafe threadSafe = new ThreadSafe(); Thread t1 = new Thread(threadSafe); Thread t2 = new Thread(threadSafe); Thread t3 = new Thread(threadSafe); Thread t4 = new Thread(threadSafe); t1.start(); t2.start(); t3.start(); t4.start(); } }运行结果
tickets:10 tickets:9 tickets:8 tickets:7 tickets:6 tickets:5 tickets:4 tickets:3 tickets:2 tickets:1