一、线程概念:
程序:program,是一个指令的集合
进程:process,正在执行的程序,是一个静态的概念
- 进程是程序的一次静态执行过程,占用特定的地址空间 每个进程都是独立的
线程:thread,是一个单一的连续控制流程
- 线程又被称为轻量级进程
- 一个进程可以拥有多个并行的线程
- 一个进程中的线程共享相同的内存单元或者内存地址空间,可以访问相同的变量和对象,而且他们从同一堆中分配对象,通信、数据交换、同步操作
- 由于线程间的通信是在同一地址空间进行的,所以不需要额外的通信机制,这就使得通信更简便而且传递的速度更快
概括:一个进程中最少有一个线程,线程共享进程中的代码和数据空间,进程是操作系统资源分配的基本单位,而线程是处理任务调度和执行的基本单位,进程崩溃后,线程一定死掉
二、实现线程的两种方式:
package com.lzw.java_thread.create;
import javax.annotation.processing.Completion;
import java.security.PublicKey;
/**
* 实现线程的两种方式:
* 第一种:继承Thread类
* 1.必须要继承Thread类
* 2.必须要重写run方法,指的是需要执行的核心逻辑
* 3.线程在启动的时候,不要直接调用run方法,需要通过start()来进行调用
* 4.每次运行相同的代码,出来的结果可能不一样,原因在于多线程谁先抢占资源无法进行人控制(包括更改优先级,也只是提高被调用的可能)
* Runable接口和Thread类实现是使用了proxy代理的设计模式
*/
public class ThreadDemo extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//打印当前进程的进程名获取当前进程用Thread.currentThread(),再获取当前进程的名字使用getName()方法
System.out.println(Thread.currentThread().getName()+"-----"+i);
}
}
public static void main(String[] args) {
ThreadDemo threadDemo = new ThreadDemo();
threadDemo.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"======"+i);
}
}
}
package com.lzw.java_thread.create;
/**
* 第二种:实现Runable接口
* 1.实现Runable接口
* 2.重写run方法
* 3.Runable接口只有run方法,没有start方法,创建Thread对象将创建的Runable子类实现作为thread的构造参数
* 4.通过thread.start()进行启动
*/
public class RunableDemo implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"------"+i);
}
}
public static void main(String[] args) {
RunableDemo rbd = new RunableDemo();
Thread td = new Thread(rbd);
td.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"====="+i);
}
}
}
三、线程的生命周期
- 新生状态: 当创建好当前线程对象后,没有启动之前(调用start()之前)。
- 就绪状态:档对应的线程创建后,调用start()方法之后,所有的线程会添加到一个就绪队列中,所有的线程同时去抢占cpu资源 。
- 运行状态:当前进程获取到cpu资源后,就绪队列中的线程回去抢占资源,谁先抢到谁执行,执行的过程叫做运行状态 。
- 死亡状态:当前运行中的线程正常执行完所有的代码逻辑或者因异常情况导致程序结束叫做死亡状态。进入的方式:
(1)正常运行完成且结束。(2)人为中断,如使用stop方法 。(3)程序抛出未捕获的异常 - 阻塞状态:在程序运行过程中,发生某些异常情况,导致当前进程无法顺利执行下去,此时会进入阻塞状态,进入阻塞状态的原因消除后,阻塞状态会再次进入到就绪状态等待抢占资源执行
进入的方式:(1) sleep方法 (2)等待io资源 (3)join方法–代码中的执行逻辑。
四、两种方式的选择
- 原因一:java是单继承语言,那就是如果我们的雷已经继承了Thread类,但是又遇到一个必须要继承的类(如小程序必须继承的Applet类),这样就麻烦了。所以建议使用Runable接口方式
- 原因二:资源共享时,Runnable类更能方便资源共享,同一份资源,多个代理访问,如下篇文章中的卖票小练习。