一、多线程的目的是为了通过提高CPU利用率来减少代码运行时间
首先判断你的项目是否必须使用多线程,如果没有什么高并发或者多次重复查询的代码是没有什么必要去创建多线程应用的
如果你的项目必须使用多线程,那么就得学习多线程,最后面有测试代码,直接复制测试
二、多线程有三种方式
1、继承 Thread 类,然后实现重写 run 方法
以售票系统为例
前面的是 start 方法结果,后面的是 run 方法结果
2、实现 Runnable 接口,和 Thread 一样的代码,只是将 extends Thread 变为 implements Runnable
*注:那么问题就来了,既然这两种方法没什么区别,为什么还要创造出来两种方法了
这就是 Thread 和 Runnable 之间的区别了
· 和所有的接口与类的区别一样,类有继承的局限性,而接口可以继承多个,并不会对类产生影响
我只能想到这一个好处,其他的希望大佬们提出来,我可以借鉴借鉴
3、实现Callable接口通过FutureTask包装器来创建Thread线程
4、使用ExecutorService、Callable、Future实现有返回结果的线程
*注:后面两种方法我并没有使用过,而且近期也不是很想了解,所以等以后有机会在补全吧
三、售票代码
public class ModeTest extends Thread{ //票数,在主方法中传入的参数 private int poll ; //已售票数 private int num = 0; private List<String> list = new ArrayList<>(); private static NumberFormat nf = NumberFormat.getInstance(); static{ //目的是固定数字长度为 4 位 nf.setMinimumIntegerDigits(4); nf.setGroupingUsed(false); } //重载方法 public ModeTest(){} public ModeTest(int poll){ this.poll = poll; } //重写方法 public void run() { while(true){ //加入锁的目的是为了防止在上一个用户还没有释放资源的时候第二个用户已经获取到了第一步的资源,造成 不可重复读 数据 synchronized (this) { if (num >= poll) { System.out.println("票已售完"); return; } //获取当前售票窗口名称,需要在创建线程时定义 String tName = Thread.currentThread().getName(); //售票量 num++; //代表售票的动作 System.out.println(tName + "\t出售\t" +nf.format(num)); } try { //每次售票后休息 0.1 秒 Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args) { //创建线程 ModeTest method = new ModeTest(100); String windows = "ABCDE"; //循环开启线程 for(int i = 0; i<windows.length();i++){ Thread te = new Thread(method, "柜台"+windows.charAt(i)); //在这为什么用 start,而不用 run 呢 //因为 run 只是运行了方法,并不会创建线程,也就是如果用 run //那么方法会通过前后顺序展示出来,开头的执行完才会去执行后面的 te.start(); } } } |