讲线程之前要了解:进程间的通信(Inter-Process Communication IPC): 理论上,进程之间是独立的,但实际上往往是多个进程之间的互相配合完成复杂的工作。例如:使用MySQL时,通过workbench进程和mysql服务器进程进行通信,来实现数据的增删查改。因此就有了进程之间交换数据的必要性。 问题是:OS进行资源分配是以进程为基本单位进行分配的,包括内存。分配给A进程的内存不会在分配给B进程。所以,进程之间通过内存来进行数据交换的可能性完全不存在。A,B进程之间被隔离了。 此时,OS提供了一套机制,用于让进程之间进行必要的数据交换——进程间通信。 ⭐进程间通信的常见方式:
package com.how_to_start_thread.demo2; public class MyThread extends Thread{ @Override public void run() { System.out.println("MyThread类下的run方法中的语句,会运行在子线程中"); } }
package com.how_to_start_thread.demo2; public class Main { public static void main(String[] args) { MyThread t=new MyThread(); t.start(); System.out.println("Main类下的main静态方法中的语句,会运行在主线程中"); } }
第一种运行结果: 第二种运行结果: 两种演示结果是随机出现的,原因是:从子线程进入到就绪队列的这一刻其,子线程和主线程在地位上就完全平等了。所有哪个线程被选中去分配CPU,是完全随机的。先执行子线程中的语句还是主线程中的语句,理论上都是可能的。 ⭐但是大概率都是主线程中的先打印先执行的,为什么?(第一种结果) t.start() 是主线程语句,换言之,这条语句被执行了,说明主线程现在正在CPU上(主线程是运行状态)。主线程刚刚执行完t.start() 就马上发生子线程调度的概率不大,所以,大概率还是t.start() 的下一条语句先执行了。 但不否认有这种情况:(第二种结果):1.非常碰巧的在t.start() 之后,System.out.println(“Main类下的main静态方法中的语句,会运行在主线程中”);之前,发生一次线程调度。主线程的状态:运行>就绪,主线程不在拥有CPU,那么以主线程t.start() 的下一条语句不再执行。调取的时候,选中子线程调度,子线程的状态:就绪>运行,子线程拥有CPU,就会执行子线程的语句。
package com.how_to_start_thread.demo2; public class ErrorMain { public static void main(String[] args) { MyThread t =new MyThread(); t.start(); t.start(); } }
以上情况原因:一个已经调用过start() 就不能在调用start() 了。t.start() 只运行工作在“新建”状态下。否则会报错:非法线程状态异常。 ⭐还需要注意的点:不能调用成run() 方法,调用成run() 方法就和线程没关系了。完全是在主线程下运行代码。 如图示: ——————————————— 什么情况下会出现线程调度?(开始选择新的线程分配CPU) 第一种:CPU空闲 1.(运行>结束)当前运行着的CPU执行结束。 2.(运行>阻塞)等待外部条件。 3.(运行>就绪)线程主动放弃。 第二种:被调度器主动调度 1.高优先级线程抢先。 2.时间片耗尽(这种情况比较常见)。 在多线程中,明明代码是固定的,但会出现的现象是随机的可能性,主要原因就是调度的随机性体现在线程的运行过程中。 如图示: 运行结果不是唯一的: 我们写的无论示Thread的子类还是Runnable的实现类,只是给线程启动的“程序”。所以同一个程序,可以启动多个线程。