并发基础(一) 线程介绍
一、线程的简介
线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个应用程序可以看做是一个进程,一个进程可以创建多个线程,进程的任务就是交给这些线程来完成。
线程基础知识点可以总结为几点:
- 线程是程序中的执行线程。java虚拟机允许应用程序并发地运行多个执行线程。
- 每个线程都有一个优先级,高优先级线程的执行优先于低级优先级线程。但不应该通过设置线程优先级的方式来安排线程的执行顺序,后续将会细说。
- 每个线程都可以或者不标志为一个守护线程。即在java中,线程分为两类:用户线程 和 守护线程。
- 当java虚拟机启动时,都会有一个非守护线程(即用户线程)启动运行。这个线程通常是调用指定类的main方法。简单来说,当你执行一个类的main方法时,其实是作为一个线程在运行,即为main线程。
- 线程在操作系统中是不拥有资源, 线程是共享进程的资源。即属于同一个进程的多个线程之间是对资源可能要进行互斥访问。这就要涉及到锁的概念。同时在JVM中,除了用锁来解决并发的问题外,还可以让每个线程拥有私有资源---线程副本(ThreadLocal),这样,线程就不需要竞争资源。
二、用户线程与守护线程
守护线程:
守护线程则是用来服务用户线程的,可以简单理解为后台运行线程。(操作系统里面是没有所谓的守护线程的概念,只有守护进程一说,但是Java语言机制是构建在JVM的基础之上的,意思是Java平台把操作系统的底层给屏蔽起来,所以它可以在它自己的虚拟的平台里面构造出对 自己有利的机制,而语言或者说平台的设计者多多少少是受到Unix思想的影响,而守护线程机制又是对JVM这样的平台凑合,于是守护线程应运而生);
守护线程使用的情况较少,但并非无用,举例来说,JVM的垃圾回收、内存管理等线程都是守护线程。还有就是在做数据库应用时候,使用的数据库连接池,连接池本身也包含着很多后台线程,监控连接个数、超时时间、状态等等。
注意:
1、JRE判断程序是否执行结束的标准是所有的前台执线程行完毕了,而不管后台线程的状态,因此,在使用后台线程候一定要注意这个问题。
也就是说,当进程中所有非守护线程已结束或退出时,即使仍有守护线程在运行,进程依旧会结束。
也就是说,当程序结束时,守护线程有可能依然未退出。
2、基于第一点,守护线程是不能用于逻辑业务计算的,否则很可能还没有计算出结果,程序就结束了。
守护线程的设置:
默认情况下,创建的线程默认是用户线程。如果要将此线程变成守护线程,则要在线程启动前调用Thread 类的 setDemo()方法,标志为守护线程。
setDemo()方法详解:
public final void setDaemon(boolean on)将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
该方法必须在启动线程前调用。
该方法首先调用该线程的 checkAccess 方法,且不带任何参数。这可能抛出 SecurityException(在当前线程中)。
参数:
on - 如果为 true,则将该线程标记为守护线程。
抛出:
IllegalThreadStateException - 如果该线程处于活动状态。
SecurityException - 如果当前线程无法修改该线程。
另请参见:
isDaemon(), checkAccess()
例子:
//这是一个很简单的线程,没有指定任何的任务
Thread t =new Thread();
//判断刚创建的线程t是不是守护线程
if(t.isDaemon()){
System.out.println("线程是守护线程");
}else{
System.out.println("线程是用户线程");
}
//将线程t设置为 守护线程
t.setDaemon(true);
//线程启动,注意:必须在线程启动前调用setDaemon()才有效
t.start();
运行结果:
线程是用户线程