线程初步学习(一)
本文是通过整理学习时查阅的资料总结出来的笔记,欢迎各位同为小白的萌新们学习参考- 本文为线程相关概念总结
什么是线程和进程
进程:
一个内存中运行的应用程序。每个进程都有自己的独立的内存空间,一个进程可以有多个线程,例如在windows系统中运行的xx.exe应用,既是一个进程。
线程:
进程中的一个任务执行单元,,负责当前进程中程序的执行,一个进程至少有一个线程,多个线程可以共享数据。
线程的并行,并发,和串行
并行:
单位时间内,多个处理器或多核处理器同时处理多个任务。例如两个并排的跑道同时有两个运动员赛跑。
并发:
多个任务在同一个cpu上,按细分的cpu时间片交替执行(因为cpu切换时间极短,两个任务在外界看来几乎是同时执行)。例如同一个跑道上有两个运动员同时起步赛跑。
串行:
有多个任务,由同一个线程按顺序去执行。由于任务和方法都在同一个线程上执行,便不存在线程不安全问题。例如同一个跑道,两个运动员一前一后排列跑步,不会发生横向碰撞
什么是多线程,多线程的优缺点
多线程:
指程序中包含多个执行单元,即在一个程序中同时运行多个不同的线程,各自执行不同的任务
多线程的好处:
提高cpu利用率。在多线程程序中,一个线程必须等待时,cpu并未等待,而是运行另外的线程,从而在大大的提高了程序的效率。
多线程的缺点:
- 线程需要占用内存,线程越多占用的内存也就越多。
- 多线程之间需要协调管理,所以需要cpu时间跟踪线程。
- 线程之间对共享资源的访问会相互影响
什么是上下文切换
在多线程编程中,线程数一般都会大于cpu核心的个数,而一个cpu核心在任意时刻只能被一个线程使用,那么其他的线程怎么办呢?
为了让所有线程都能获取到cpu的有效执行,cpu采用的策略是为每个线程分配时间片并轮流去执行。当一个线程的时间片用完的时候,就会重新处于就绪状态,让其他线程去获取有效时间片执行,这个过程就是一次上下文切换。
总结来说:一个线程的cpu时间片用完的时候,会记录下自己的执行状态,以便下次切换到这个线程执行时,可以继续加载到前一次的执行状态。一个任务从保存状态到下一次加载就是一次上下文切换。
这里记录状态的是jvm中的程序计数器,后续介绍jvm组成。
守护线程和用户线程
用户线程:
运行在前台,执行具体的任务,如程序的主线程,连接网络的子线程都是用户线程。
守护线程:
运行在后台,为其他前台线程服务,也可以说守护线程是jvm中非守护线程的“佣人”。一旦所有的用户线程都结束运行,守护线程会随jvm一起结束工作。
main函数所在的线程就是一个用户线程,main启动时jvm内部同时还会启动很多守护线程,例如垃圾回收线程。
有一点比较明显的区别,用户线程结束时,jvm退出,而此时无论有没有正在执行的守护线程,都不会影响到jvm退出。
注意事项:
- 在守护线程中产生的新线程也是守护线程。
- 不是所有任务都可以分配给守护线程来执行,比如读写操作或者计算逻辑。(可能出现读写到一半jvm退出)
- 守护(Deamon)线程中不能依靠finally块中的内容来确保代码的执行(释放资源等操作),因为上面也说了,当所有用户线程都结束,守护线程也就没必要存在了,jvm会直接退出,在Deamon中finally的语句就很可能无法执行。
创建线程的四种方法
- 继承Thread类
//继承Thread类,重写run()
static class Thread1 extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread()+"run()方法正在执行...");
}
};
public static void main(String[] args) {
Thread1 thread1=new Thread1();
thread1.start();
System.out.println(Thread.currentThread()+"main()方法正在执行...");
}
Thread[main,5,main]