一、进程 线程
进程:一个进程来对应一个程序,
每个进程对应一定的内存地址空间,并且只能使用它自己的内存空间,各个进程间互不干扰。
进程保存了程序每个时刻的运行状态,这样就为进程切换提供了可能。当进程暂停时,它会保存当前进程的状态(比如进程标识、进程的使用的资源等),在下一次重新切换回来时,便根据之前保存的状态进行恢复,然后继续执行。
对于单核计算机来讲,在同一个时间点上,游戏进程和音乐进程是同时在运行吗?
不是。 因为计算机的 CPU 只能在某个时间点上做一件事。
由于计算机将在“游戏进程”和“音乐进程”之间频繁的切换执行,切换速度极高,人类感觉游戏和音乐在同时进行。多进程的作用不是提高执行速度,而是提高 CPU 的使用率。
线程:一个进程就包括了多个线程,每个线程负责一个独立的子任务。这些线程是共同享有进程占有的资源和地址空间的。
这样在用户点击按钮的时候,就可以暂停获取图像数据的线程,让UI线程响应用户的操作,响应完之后再切换回来,让获取图像的线程得到CPU资源。从而让用户感觉系统是同时在做多件事情的,满足了用户对实时性的要求。
进程让操作系统的并发性成为可能,而线程让进程的内部并发成为可能。
多线程优点:参考多线程的优点
资源利用率更好
程序设计在某些情况下更简单
程序响应更快
多线程缺点:参考多线程的代价
设计更复杂
上下文切换的开销
增加资源消耗
上下文切换:
对于单核CPU来说(对于多核CPU,此处就理解为一个核),CPU在一个时刻只能运行一个线程,当在运行一个线程的过程中转去运行另外一个线程,这个叫做线程上下文切换(对于进程也是类似)。
由于可能当前线程的任务并没有执行完毕,所以在切换时需要保存线程的运行状态,以便下次重新切换回来时能够继续切换之前的状态运行。
所以一般来说,线程上下文切换过程中会记录程序计数器、CPU寄存器状态等数据。
说简单点的:对于线程的上下文切换实际上就是存储和恢复CPU状态的过程,它使得线程执行能够从中断点恢复执行。
虽然多线程可以使得任务执行的效率得到提升,但是由于在线程切换时同样会带来一定的开销代价,并且多个线程会导致系统资源占用的增加,所以在进行多线程编程时要注意这些因素。
二、创建、启动线程
继承Thread类
public classTest {public static voidmain(String[] args) {
MyThread thread= newMyThread();
thread.start();
}
}class MyThread extendsThread{private static int num = 0;publicMyThread(){
num++;
}
@Overridepublic voidrun() {
System.out.println("主动创建的第"+num+"个线程");
}
}
实现Runnable接口
public classTest {public static voidmain(String[] args) {
Thread thread= new Thread(newMyRunnable());
thread.start();
}
}class MyRunnable implementsRunnable{publicMyRunnable() {
}
@Overridepublic voidrun() {
System.out.println("子线程ID:"+Thread.currentThread().getId());
}
}
注意:创建并运行一个线程调用start()方法 而不是run()
三、Thread类/线程状态
1)getId 用来得到线程ID
2)getName和setName 用来得到或者设置线程名称。
3)getPriority和setPriority 用来获取和设置线程优先级。
4)setDaemon和isDaemon
用来设置线程是否成为守护线程和判断线程是否是守护线程。
守护线程和用户线程的区别在于:守护线程依赖于创建它的线程,而用户线程则不依赖。
举个简单的例子:如果在main线程中创建了一个守护线程,当main方法运行完毕之后,守护线程也会随着消亡。而用户线程则不会,用户线程会一直运行直到其运行完毕。在JVM中,像垃圾收集器线程就是守护线程。
5)Thread类有一个比较常用的静态方法currentThread()用来获取当前线程。
6)start方法
7)run方法
8)sleep方法 sleep相当于让线程睡眠,交出CPU,让CPU去执行其他的任务。sleep方法不会释放锁。
9)yield方法
调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。不会释放锁。
调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态。
10)join方法
假如在main线程中,调用myThread.join()方法,则main方法会等待thread线程执行完毕或者等待一定的时间。
如果调用的是无参join方法,则等待thread执行完毕,如果调用的是指定了时间参数的join方法,则等待一定的事件。
11)interrupt方法
详细讲解中断:
单独调用interrupt方法可以使得处于阻塞状态的线程抛出一个异常,它可以用来中断一个正处于阻塞状态的线程。
举例:
控制台输出:
进入睡眠状态
得到中断异常
run方法执行完毕
public classTest {public static void main(String[] args) throwsIOException {
Test test= newTest();
MyThread thread= test.newMyThread();
thread.start();try{
Thread.currentThread().sleep(2000);
}catch(InterruptedException e) {
}
thread.interrupt();
}class MyThread extendsThread{
@Ov