1. 守护线程Daemon
什么是守护进程?
守护线程:也叫后台线程,脱于控制终端,用来服务用户线程。例如GM垃圾回收 处理后台的工作的线程
用户线程:一般用户执行的线程。
t1.setDaemon(Boolean b);
设置线程为守护线程,true 即设置为守护线程 ,false 非守护线程,默认为false
注意:setDaemon方法只能线程启动之前使用,如果对于一个线程已经死亡或者未启动,那么设置setDaemon会抛出IllegalThreadStateException
t1.isDaemon()
获取当前线程是否为守护线程。
守护线程的生命周期
依赖于用户线程,当用户线程存在,守护线程就会存在,反之,用户线程不存在时,守护线程就会消亡
为什么会有守护线程?
守护线程具有自动结束生命周期的特征,当用户线程全部处于终止状态,只剩下守护线程,那么JVM会退出,守护线程自动结束。
假设GM是非守护线程,主函数main结束工作,但JVM无法结束工作,因为GM还在正常工作。
什么时候需要守护线程?
它也叫:后台线程,它可以经常用作执行一些后台任务,当关闭JVM时。希望自动关闭某些线程,则可以将这些线程设置为守护线程。
2. 线程的生命周期
State枚举类
NEW, 线程开始
RUNNABLE,运行和就绪
BLOCKED,阻塞状态
WAITING,
TIMED_WAITING,
TERMINATED;终止
new:新建状态
使用new’创建线程处于新建状态,此时和其他Java对象一样在Java堆中分配内存,在这种状态下,使用**getState()**可以获取线程的状态。
Runable:就绪状态/运行状态
在Java中Runable状态表示正在占用cpu或者等待cpu资源
在操作系统中将Java的Runable状态分为两个状态:Runable
和Running
状态。
1.Runable: 就绪状态
当线程被创建后,调用**start()**方法,线程就处于就绪状态,当其他条件都满足时,可等待CPU的使用权
2.Running:运行状态
在运行状态的线程即得到CPU的使用权,执行线程代码,只能是就绪状态到运行状态
Blocked:阻塞状态
指线程因为某些原因放弃CPU使用权eg:缺少资源 IO,锁等,暂停运行,即处于阻塞状态。
Waiting:等待状态
当前状态,因为线程对象调用了**wait()**方法,JVM就会将线程方法置入等待池中
Timed_Waiting:超时等待
调用**Sleep(long time), join(long time)**会时线程处于睡眠状态
Terminated:终止状态
当线程执行 **run()**方法结尾处,进入终止状态,表示该线程的生命周期结束。
线程状态转化图
状态转化的方法
start() 启动新线程
启动一个新线程,必须首先调用,且只能调用一次,不能重复调用
JNI:JAVA NATIVE INTERFICE Java本地方法接口
run():子线程执行体
可重复调用,
不需要单独由对象调用,start方法启动后,会主动调用run方法
直接调用和通过调用start方法调用run的区别:
直接调用: 就是普通方法调用,还是在主线程中调用,而非启动一个子线程
yiled():线程让步
Thread.yiled()
暂停当前线程的执行,让步于其他优先级相同或优先级更高
等待的线程获取CPU的调度,若没有优先级相同或更高的线程,则此线程会继续运行
运行——》就绪,等待线程调度,需要注意的是仅仅让出CPU资源
此方法是static方法,直接调用不需要对象
public static native void yield();//直接通过类名调用
注意:1. 调用yiled方法的线程进行让步,OS进行调度的下一个线程会不会是让步的线程? 会的,如果没有大于的等于让步线程的优先级,即会调度让步的线程
2. 为什么yiled是静态的,而不是通过对象调用?因为让步的线程。不一定处于运行状态的线程。
答
:因为yiled方法只能是正在执行的线程让出CPU的使用权,假设使用线程对象调用yiled方法,会产生错觉让当前的线程对象让步,当前执行的线程不一定是正在运行的线程,必须是占用CPU
的线程
sleep():线程休眠
Thread.sleep()
通过类名调用。
public static native void sleep(long millis) throws InterruptedException;
特点:
- 线程休眠,调用的线程会进入休眠。
- sleep方法是Thread的静态方法
- sleep方法可以传入参数,即会有时间限制,时间结束,继续运行。
- 在休眠的millis中可以调用**interrupt()**调用,会抛出 InterruptedException的异常中断睡眠。
Join(): 线程合并
t.join()
t.join(long mills)
t.join(long mills,int nanos;)
特点:1. Join方法提供了线程的有序进行,将并发执行合并为串行执行。
在线程A中线程B调用B.join() , 则A线程会在B线程执行完成后执行,按照B,A执行。
join方法的本质 还是 wait()方法
进入等待状态 waitting 或 Timed_waiting 状态
- join() 和 sleep() 一样被中断会抛出***InterruptedException***的异常。不同的是join会
释放
锁,因为调用了wait(),而sleep()会一直保持锁 - 子线程结束后,子线程的this.notifyAll()会被调用,join()返回,父线程只要获取到锁和CPU,就可以继续运行下去了。
public final void join() throws InterruptedException {
join(0);
}
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
public final synchronized void join(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
join(millis);
}
Interrupt():中断线程
t.interrupt()
t.isInterrupt()
判断是否处于中断操作
特点:
- 只能中断处于
“阻塞状态”
的线程(sleep . wait , join等方法进入阻塞状态。)在当前状态调用 interrupt方法,就会抛出 InterruptedException。 - 若当前线程是正在运行状态,调用interrupt方法,线程还会继续执行,直到发生sleep . wait , join等方法,才会进入到阻塞状态,继而抛出 InterruptedException来中断阻塞状态。原因是每个线程都有个线程标志位 解释:当调用interrupt方法时,会变更该线程的标志位(1个比特位,0->1) 当线程进入阻塞状态时,会判断标志位是否变更,如果变更,立即终止该阻塞状态,随即抛出异常。
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag 只是设置中断标志2
b.interrupt(this);
return;
}
}
interrupt0();
}
private native void interrupt0();
3.线程优先级 Priority
t1.setPriority();
设置线程优先级
t1.getPriority()
获取线程的优先级
public final static int MIN_PRIORITY = 1;最小优先级
public final static int NORM_PRIORITY = 5;默认优先级
public final static int MAX_PRIORITY = 10; 最大优先级
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY (10)|| newPriority < MIN_PRIORITY(1)) {先判断优先级的安全
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
/**
* Returns this thread's priority.
*
* @return this thread's priority.
* @see #setPriority
*/
public final int getPriority() {
return priority;
}
特点:
- Java中线程的优先级只是它执行的概率比较大,而优先级低的线程并不是没有机会,概率相对低。
- 优先级范围 1-10.线程的。
- 线程的优先级具有继承性,若线程A内创建线程B,B的优先级会和A的优先级相等。
4.线程调度
用户级调度
调用相应的方法来改变线程的状态而达到线程的调度
- 调整线程的优先级
- 线程睡眠:sleep
- 线程等待:wait
- 线程让步:yield
- 线程合并:join
系统级调度
FIFO:先进先出算法
SJF:最短作业优先算法
RR:时间片轮转法
HPF:最高优先级算法
一般OS 基于RR 和 HPF 基于时间片的有限级调度。
5.并发与并行概念
并发指的是多个线程操作同一个资源,不是同时执行,而是交替执行,单核cpu,只不过 cpu时间片很短,执行速度很快,看起来同时执行
并行才是真正的同时执行,多核cpu。每一个线程使用一个单独的cpu运行