1. 基本概念
进程:每个进程对应一个程序,对应一定的内存地址空间,且只能使用其自己的内存空间,进程间互不干扰。进程保存了程序每个时刻的运行状态,进程暂停时会保存其当前的状态(进程标识、进程使用的资源等),下次切换回来时,根据之前保存的状态进行恢复,然后继续执行。
线程:一个进程包含多个线程,但这些线程共享进程占用的资源和地址空间。
进程是操作系统进行资源分配的基本单位,而线程是操作系统进行调度的基本单位。
进程使得操作系统的并发性成为可能,而线程使得进程内部的并发成为可能。
2. Java中的进程、线程
Java中,一个应用程序对应一个JVM实例(亦称JVM进程),名字一般默认为java.exe或javaw.exe。
Java采用单线程编程模型,即程序中没有主动创建线程的话,默认只会创建一个线程,称为主线程,但不代表JVM中只有一个线程,JVM实例在创建的时候,会同时创建很多其他线程(如垃圾收集器线程)。
Java中创建线程
2种方式,1. 继承Thread类;2. 实现Runnable接口。
Java中创建进程
2种方式:
通过ProcessBuilder.start方法创建;
ProcessBuilder.start方法中调用了ProcessImpl.start方法,ProcessImpl类本身继承了Process类,而在ProcessImpl.start方法中new了一个ProcessImpl实例并返回。通过Runtime.exec方法创建。
Runtime.exec方法中调用了ProcessBuilder.start方法。Runtime,即运行时,表示当前进程所在的虚拟机实例。
用法:
通过ProcessBuilder.start方法
ProcessBuilder pb = new ProcessBuilder("cmd","/c","ipconfig/all"); Process process = pb.start(); Scanner scanner = new Scanner(process.getInputStream()); while(scanner.hasNextLine()){ System.out.println(scanner.nextLine()); } scanner.close();
通过Runtime.exec方法
String cmd = "cmd "+"/c "+"ipconfig/all"; Process process = Runtime.getRuntime().exec(cmd); // 单例方式获取Runtime实例 Scanner scanner = new Scanner(process.getInputStream()); while(scanner.hasNextLine()){ System.out.println(scanner.nextLine()); } scanner.close();
3. Thread类的使用
线程的状态及对应的方法
线程的状态
线程包括5个状态:创建(new)、就绪(runnable)、运行(running)、阻塞(blocked)[time waiting、waiting]、消亡(dead)。
线程的创建状态,new一个线程。
线程创建后,不会立即进入就绪状态,因为线程运行需要一些条件(如内存资源,线程私有的程序计数器、Java栈、本地方法栈),只有条件满足了才进入就绪状态。调用start方法会为线程分配需要的资源。
线程进入就绪状态后,不代表立即能获取CPU执行时间,当得到CPU执行时间后,才进入运行状态。
线程运行过程中,可能有多个原因导致线程无法继续运行,如sleep()、join()/wait()、同步块阻塞。对应time waiting、waiting、blocked状态。
上下文切换
线程的上下文切换实际上就是存储和恢复CPU状态的过程,它使得线程能够从中断点恢复执行。
Thread类中的方法
线程优先级:最大10,最小1,默认5。
线程运行相关方法:
- start。
启动一个线程,为线程分配需要的资源。 - run。
- sleep。
交出CPU,进入阻塞状态,不释放锁。 - yield。
交出CPU,重回就绪状态,不释放锁。 - join。
等待thread执行完毕或等待指定时间,内部使用wait实现。交出CPU,进入阻塞状态,释放锁。 - interrupt。
中断处于阻塞状态的线程(使其抛出中断异常)。
线程属性相关方法:
- getId。
- getName、setName。
- getPriority、setPriority。
- setDaemon、isDaemon。 守护线程依赖于创建它的线程,而用户线程不依赖。创建守护线程的线程运行完毕后,守护线程也会随之消亡,而用户线程会一直运行到其结束。
获取当前线程的静态方法Thread.currentThread()。