线程和进程相关
一、 程序,进程,线程
1. 概念
程序
程序只是一组指令的有序集合,它本身没有任何运行的含义,它只是一个静态的实体
进程
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
线程
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
2. 区别
- 程序是静态的,进程和线程是动态的
- 进程是拥有资源的基本单位
- 线程是调度和分配的基本单位
3. 联系
- 一个程序可以对应多个进程(例如 QQ),一个进程可以对应多个线程
- 一个线程只能隶属于一个进程,而一个进程可以有多个线程,但至少有一个线程
- 线程在执行过程中,需要协作同步。不同进程的线程之间要利用消息通信的方法实现同步(进程间通信方式:管道、消息队列、共享存储、信号量、套接字Socket、信号)
- 程序不负责申请系统资源,进程申请系统资源,线程共享线程的全部资源
4. 线程的创建方式
- 继承Thread类创建线程
public class MyThread extends Thread{//继承Thread类
public void run(){
//重写run方法
}
}
public class Main {
public static void main(String[] args){
new MyThread().start();//创建并启动线程
}
}
- 实现Runnable接口创建线程
public class MyThread2 implements Runnable {//实现Runnable接口
public void run(){
//重写run方法
}
}
public class Main {
public static void main(String[] args){
//创建并启动线程
MyThread2 myThread=new MyThread2();
Thread thread=new Thread(myThread);
thread().start();
//或者 new Thread(new MyThread2()).start();
}
}
- 使用Callable和Future创建线程
public class Main {
public static void main(String[] args){
MyThread3 th=new MyThread3();
//使用Lambda表达式创建Callable对象
//使用FutureTask类来包装Callable对象
FutureTask<Integer> future=new FutureTask<Integer>(
(Callable<Integer>)()->{
return 5;
}
);
new Thread(task,"有返回值的线程").start();//实质上还是以Callable对象来创建并启动线程
try{
System.out.println("子线程的返回值:"+future.get());//get()方法会阻塞,直到子线程执行结束才返回
}catch(Exception e){
ex.printStackTrace();
}
}
}
- 使用线程池例 如用Executor框架
具体细节百度
5. 多线程
概念:
多线程是在一个进程中包含多个并发执行的控制流
优点:
系统性能获得很大的提升,具体表现为:快速切换线程、减少系统管理开销、线程通信易于实现。并发程度提高,节省内存空间等
二、 Thread类和Runnable接口的异同
相同点
都是“多线程的实现方式”,线程的运行都是执行run()方法,线程的启动都是start()方法
不同点
- Thread是类,Runnable是接口
- Thread类本身就是实现了Runnable接口的类
- Java只支持单集成,而接口可以多实现,因此Runnable接口具有更好的扩展性
- 推荐使用Runnable接口实现多线程
三、 线程的生命周期
线程的生命周期包含5个阶段,包括:创建→就绪→运行→阻塞→销毁
- 创建:使用new关键字new一个线程
- 就绪:调用线程的start()方法后,这时候县城处于等待CPU分配资源阶段,谁先抢到CPU资源,谁开始执行
- 运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run()方法定义了现成的操作和功能
- 阻塞:在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态,比如sleep()、wait()之后线程就处于了阻塞状态,这时候需要其他的机制将处于阻塞状态的线程唤醒,比如调用notify()或者notifyAll()方法。唤醒线程不会立刻执行run()方法,它们需要再次等待CPU分配资源进入运行状态
- 销毁:如果线程正常执行完毕后或线程被提前强制性的终止或者出现异常导致结束,那么线程就要被销毁,释放资源
不负韶华,只能朝夕