JavaSE 线程(上)
一、基本概念: 程序 - 进程 - 线程
-
**程序(program)**是为完成特定任务、用某种语言编写的一组指令的集合。就是一段代码,静态对象。
-
**进程(process)**是程序的一次执行过程,或是正在运行的一个程序。动态过程:有自身的产生、存在和消亡的过程。
- 比如:QQ,网易云音乐。
- 程序是静态的,进程是动态的。
-
**线程(thread)**是进程的细化,是一个程序内部的一条执行路径。
- 如果一个程序可以同时执行多个线程,就是支持多线程的。
可以这么认为:程序就是静止的代码,进程就是运行着的代码,线程就是运行时代码的支流。
何时使用多线程
-
程序需要同时执行两个/多个任务。
-
程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索等。
-
需要一些后台运行的程序时。
二、多线程的创建和启动
Java语言的JVM允许程序运行多个线程,它通过java.lang.Thread类来实现。
Thread类的特性
- 每个线程都是通过某个特定Thread对象的run()方法来完成操作,经常把run()方法的主体成为线程体。
- 通过Thread对象的start()方法来启动这个线程,本质上是运行run()方法。
1 继承Thread类实现多线程
-
创建步骤
- 定义子类继承Thread类
- 子类中重写Thread类中的run方法
- 创建Thread子类对象,即创建了线程对象
- 调用线程对象start方法:启动线程,调用run方法
-
案例展示:
扫描二维码关注公众号,回复: 9965616 查看本文章package com.thread; /** * 继承Thread类的方式实现多线程 */ public class TestThread extends Thread{ @Override public void run() { System.out.println("多线程运行的代码"); for (int i = 0; i < 5; i++) { System.out.println("这是多线程的逻辑代码" + i); } } }
package com.thread; public class Test { public static void main(String[] args) { Thread t0 = new TestThread(); t0.start(); //启动线程 System.out.println("----------------"); System.out.println("----------------"); System.out.println("----------------"); } } /*运行结果: 多线程运行的代码 ---------------- ---------------- 这是多线程的逻辑代码0 这是多线程的逻辑代码1 这是多线程的逻辑代码2 这是多线程的逻辑代码3 这是多线程的逻辑代码4 ---------------- */
-
运行结果说明:
多次运行main方法后发现,打印结果中3行分隔符与开启线程运行run()方法中打印语句是混合起来的且打印语句顺序不固定!Why?
- 因为main执行t0.start()开启多线程之后,就相当于在main方法之外开启了一个支流。
- 而这个支流代码的执行和main方法之后代码的执行就可认为是同时运行。
- 那么控制台输出的结果就是两条并行程序的运行结果总和,这个结果就需要拆开成两部分来看,总体上顺序是混乱的,但是各自来看保持自己输出顺序。
这就体现了类多线程的异步性(相对于主程序来说)
2 实现Runnable接口实现多线程
-
创建步骤
-
定义子类,实现Runnable接口
-
子类中重写接口中的run方法
-
通过Thread类含参构造器创建线程对象
-
将Runnable接口中的子类对象作为实际参数传递给Thread类的构造方法中
通俗点:3、4就是
Thread t = new Thread(new TestRunnable()); //也可加入线程名称
-
调用Thread类的start方法:开启线程,调用run方法
-
-
案例展示:
package com.thread; /** * 通过实现Runnable接口方式实现多线程 */ public class TestRunnable implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"Runnable多线程运行的代码"); for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName()+"这是Runnable多线程的逻辑代码" + i); } } }
package com.thread; public class Test2 { public static void main(String[] args) { Thread t0 = new Thread(new TestRunnable()); t0.start(); Thread t1 = new Thread(new TestRunnable(),"t-1");//可传入线程名称 t1.start(); System.out.println("----------------"); System.out.println("----------------"); System.out.println("----------------"); } } /*运行结果: t-1Runnable多线程运行的代码 t-1这是Runnable多线程的逻辑代码0 t-1这是Runnable多线程的逻辑代码1 t-1这是Runnable多线程的逻辑代码2 t-1这是Runnable多线程的逻辑代码3 t-1这是Runnable多线程的逻辑代码4 Thread-0Runnable多线程运行的代码 Thread-0这是Runnable多线程的逻辑代码0 Thread-0这是Runnable多线程的逻辑代码1 Thread-0这是Runnable多线程的逻辑代码2 Thread-0这是Runnable多线程的逻辑代码3 Thread-0这是Runnable多线程的逻辑代码4 ---------------- ---------------- ---------------- */
对运行结果的说明可查看上个案例的说明,均体现了多线程的异步性。
3 两种继承方式和实现方式的联系和区别
【区别】
- 继承Thread:线程代码存放在Thread的子类的run方法中。(重写)
- 实现Runnable:线程代码存放在接口的子类的run方法中。(实现)
【实现Runnable方式的好处】
- 避免了单继承的局限性。(因为接口可以实现间接实现多继承)
- 多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程共享同一份资源。(使用同一个实现了Runnable接口的类实例即可共享资源)
因此一般使用实现接口的方式来实现多线程!!!
使用多线程的优点
- 提高应用程序的响应。对图形化界面更有意义,可增强用户体验。
- 提高计算机系统CPU的利用率。
- 改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改。
例如: 如果有一个方法里有1000行代码,前300,中间300,最后400行这三段代码,没有因果关系,这种情况就可以使用线程处理,把前中后三段代码分别放在不同的线程中去运行,这样三段代码就是并行运行的。效率更高!
写在最后
谦卑是看别人比自己好,自卑是看别人比自己差,两者截然不同!
保持谦卑,保持自信!
To Demut and Dottie!