1. 进程和多线程的概念
1.1 进程
提到多线程就不得不提及“进程”这个概念。
进程:进程是操作系统结构的基础;是一次程序的执行;是一个程序及其数据在处理机上顺序执行时发生的活动;在程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位。
举例:
我们可以将一个正在操作系统中运行的.exe
程序理解成进程,进程是受操作系统管理的基本运行单元.
1.2 线程
线程:线程就可以理解成是在进程中独立的子任务。
多线程:多线程指的就是一个 .exe
程序同时执行多个子任务
举例:
运行QQ.exe时就有很多子任务在同时运行。比如:好友视频线程、下载文件线程、传输数据线程、发送表情线程等等,这些不同任务或者功能都可以同时运行,其中每一项任务完全可以理解成理“线程”在工作,传文件,发送图片表情等能有对应的线程在后台默默运行。
多线程的优点:使用多任务操作系统 Windows 后,可以最大限度地利用 CPU 的空闲时间处理其他的任务,比如一边让操作系统处理正在由打印机打印的数据,一般使用 Word 编辑文档。而 CPU 在这些任务之间不停地切换,由于切换的速度非常快,给使用者的感受就是这些任务似乎在同时运行。所以使用多线程技术后,可以在同一时间运行更多不同种类的任务。
小结:
有了多线程,我们就可以让程序同时做多件事情
多线程的作用:提高效率
多线程的应用场景:只要你想让多个事情同时运行就需要多线程,比如:软件中的消耗操作、所有的聊天软件、所有的服务器。
2. 并发和并行
2.1 并发
并发:在同一个时刻,有多个指令在单个 CPU 上交替执行
举例:我在打游戏的时候。又想喝可乐,于是我的右手一会拿鼠标,一会拿可乐,那么此时由于我的手速非常的快,在鼠标和可乐之间来回交替执行,此时我们就可以看作是并发,这里右手就是当做 CPU,鼠标和可乐就当做线程1和线程2,CPU 就是在这两条线程之间进行交替执行
红色的线比做 CPU ,蓝色的线比做 线程。
2.2 并行
并行:在同时一个时刻,有多个指令在多个 CPU 上同时执行
红色的线比做 CPU ,蓝色的线比做 线程。
有人会疑问了我们的电脑上不是只有一个 CPU?为啥上图有两个 CPU 呢?
但是我们的电脑的 CPU 可以分为:2核4线程、4核8线程、8核16线程、16核32线程、32核64线程等等。这里线程的数量就是电脑能同时运行的线程。
这里我们用2核心4线程举例:
它可以同时运行4条线程,所以如果你的电脑当中只有4条线程,那么它就可以不用切换的,但是如果线程越来越多,那么这4条红线就会在多个线程之间随机的进行切换,所以在计算机中并发和并行有可能同时都在发生的
3. 多线程的实现方式
3.1继承 Thread 类
步骤:
- 定义类继承
Thread
类 - 重写
run
方法 - 创建实例
- 启动线程
代码:
// 1.继承 Thread类 class MyThread extends Thread{ // 2. 重写 run方法 @Override public void run() { // 线程代码 while (true) { System.out.println("hello thread"); // sleep方法:休眠 try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } public class Test { public static void main(String[] args) { // 3. 创建实例 MyThread t = new MyThread(); // 4.启动线程 t.start(); while (true) { System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
运行结果:
【注意】:多线程是异步的,所以千万把 idea 里代码的顺序当成线程执行的顺序,线程被调用的时机是随机的。
3.2 实现 Runnale 接口
步骤:
- 实现
Runnale
接口 - 重写
run
方法 - 创建实例,调用
Thread
的构造方法时将Runnable
对象作为target
参数 - 启动线程
代码:
// 1. 实现Runnable 接口 class MyRunnable implements Runnable { // 重写 run 方法 @Override public void run() { while (true) { System.out.println("hello Thread"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } public class Test3 { public static void main(String[] args) { // 3. 创建实例,调用 Thread 的构造方法时将 Runnable 对象作为 target 参数 Thread t = new Thread(new MyRunnable()); // 4. 启动线程 t.start(); while (true) { System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
运行结果
3.3 其他形式
- 匿名内部类创建
Thread
子类对象
代码:
public class Test4 { public static void main(String[] args) { new Thread(){ @Override public void run() { while (true) { System.out.println("hello Thread"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }.start(); while (true) { System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
运行结果:
- 匿名内部类创建
Runable
子类对象
代码:
public class Test5 { public static void main(String[] args) { new Thread(new MyRunnable()) { @Override public void run() { while (true) { System.out.println("hello Thread"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }.start(); while (true) { System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
运行结果:
lambda
表达式创建Runnable
子类对象
代码:
public class Test6 { public static void main(String[] args) { Thread t = new Thread(() -> { while (true) { System.out.println("hello Thread"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); t.start(); while (true) { System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
运行结果: