一、进程和线程的关系
什么是进程:我们可以任意正在执行的app看成一个进程,进程是操作系统中资源分分配调度的基本单位,进程是拥有自己的地址空间的,进程中至少有一条线程,线程共享着进程的地址空间,可以把进程看成线程的容器。
什么是线程:是指在java程序中同时执行多个任务的机制,每个线程都是独立的执行路径,可以同时执行不同的任务或者处理不同的数据。在多线程中,每个线程都有自己的程序计数器、堆栈和局部变量,但是它们共享进程的虚拟地址空间、全局变量和静态变量。多线程是把双刃剑,多线程的使用可以提高程序的并发性和效率,但是利用的不恰当程序就会面临未知异常甚至是程序崩溃。
深挖概念:
①程序计数器:是用于存储线程执行的下一条指令地址。每个线程都有自己的程序计数器,用于记录线程当前执行的位置。
②堆栈:是用于存储方法调用和返回的数据、参数和局部变量空间。在线程中,每个线程都有自己的堆栈,用于存储线程执行过程中的数据。
由于每个线程都有自己的计数器、堆栈和局部变量,因此线程之间是相互独立的。
二、线程的启动
我们熟悉的有两种启动线程的方式:
实现Runnable 接口。
继承Thread类,重写run方法。
在这里我们通常使用第一种启动线程的方法,因为在java中只能单继承,如果使用第二种,则占用的继承名额,使得程序的扩展性降低。
代码实现:
public class MyRunnable implements Runnable{//实现Runnable接口
@Override
public void run() {
System.out.println("我们开始执行任务。。。。。。");
}
public static class MyTest {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
new Thread(mr).start();
}
}
}
我们在使用第一种方法创建线程,也就是实现Runnable接口,可以把这个实现Runnable接口的类当成一个任务,我们需要启动线程就必须创建Thread类对象,把任务传入,调用start方法,成功启动线程。
public class ThreadStart {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start();
}
}
class MyThread extends Thread{//继承Thread类
@Override
public void run() {
System.out.println("线程启动。。。");
}
}
在这里我们得注意一个点,当程序执行start方法的顺序并不代表程序启动的顺序。
package pgs0325;
public class ThreadText {
public static void main(String[] args) {
Thread t1 = new Thread(new MyThread(1));
Thread t2 = new Thread(new MyThread(2));
Thread t3 = new Thread(new MyThread(3));
Thread t4 = new Thread(new MyThread(4));
Thread t5 = new Thread(new MyThread(5));
Thread t6 = new Thread(new MyThread(6));
Thread t7 = new Thread(new MyThread(7));
Thread t8 = new Thread(new MyThread(8));
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
t7.start();
t8.start();
}
}
class MyThread implements Runnable{
private int no;
public MyThread(int no){
this.no = no;
}
@Override
public void run() {
System.out.println(no);
}
}
输出结果不是预期 1 2 3 4 5 6 7 8。
为什么会这样呢?这主要是因为任务的执行靠CPU,而处理器采用分片轮询方式执行任务,所有的任务都是抢占式执行模式,也就是说任务是不排序的。可以设置优先级,优先级高的任务可以会优先执行(多数是无效的)。任务被执行前,该线程处于自旋等待状态。
那什么是CPU时间分片?时间分片是指操作系统将CPU时间分为多个时间片,每个时间片分配给一个任务使用,任务在时间片结束前执行完毕或自行放弃CPU的使用,然后CPU将时间片分配给下一个任务。
什么是轮询?轮询是指操作系统按照一定的顺序依次轮流分配时间片给各个任务,从而实现任务的并发执行。