线程基础方法介绍及线程分类
线程基础方法
线程中有这么一些基础方法:
- start():启动线程
- run():子线程的执行体,常需要重写run()方法
- yield():线程让步
- sleep():线程睡眠
- join():线程同步
- interrupt():线程中断
start()方法
附源代码:
public synchronized void start() {
//threadStatus=0时,说明线程处于新建状态
//此处不为0时,说明线程已启动,因此抛出异常
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
//此处为第一个try语句中的启动方法
private native void start0();
start()方法中的是用来启动线程的,start()方法是不能被重复调用的。此处仅仅是启动线程,但并没有开始执行代码块,线程状态变成RUNNING(运行)状态时,才会执行代码块。
从上面的源码我们可以看出,线程的启动是依靠start0()方法的,此方法是用关键字native来修饰的,即Java线程的创建是由本地操作系统来完成的,通过调用系统的方法来启动子线程。
run()方法
附源代码:
public void run() {
if (target != null) {
target.run();
}
}
当run()方法体不为空时,使用target调用run方法。
run()方法是子线程的执行体,和其他普通方法一样,可以被重复调用,若在当前线程调用,则不会启动新线程。
yield()方法
附源代码:
public static native void yield();
yield()方法是进行线程让步的,可以看出是static和native两个关键字修饰的。
若调用yield方法时,会从RUNNING(运行)状态变成RUNNABLE(就绪)状态,线程所抢占的锁是不会释放的。
yield()会让出CPU的执行权,有操作系统决定让给谁,系统会让具有相同优先级的或更高优先级的线程获取CPU的执行权,如果没有相应优先级的线程,当前线程就会立即执行。
※注意点:
- 调用yield()方法并不等于是当前某个线程进行让步,而是现在正在运行的全部线程暂停让步,因此使用static修饰,且占用的锁不会释放。
sleep()方法
附源代码:
//参数为毫秒
public static native void sleep(long millis) throws InterruptedException;
//参数为毫秒和纳秒
public static void sleep(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");
}
//四舍五入:0.5毫秒进一||或者总时间小于1毫秒时,进一
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
sleep(millis);
}
sleep()方法是进行线程睡眠的,会抛出InterruptedException异常,哪个线程调用sleep()方法,哪个线程进入TIME_WAITING(睡眠等待)状态。
sleep()所在的线程休眠期间,线程会释放掉CPU资源给其他线程,但如果当前线程本身持有锁,锁是不会释放的,线程会由RUNNING(运行)状态进入到TIMED_WAITING(睡眠等待)状态,当到达休眠时间或者是被中断掉休眠,就会从睡眠状态进入到就RUNNABLE(就绪)态,从而等待CPU的调用。
join()方法
附源代码:
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) {
//isAlive判断子线程是否还在运行,如果参数为0会一直阻塞,线程就会不停的等待,直到其他线程通过notify等方法才能唤醒继续执行
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
//Object类下的wait()方法,是线程间通信的方法之一
public final native void wait(long timeout) throws InterruptedException;
join()方法是进行线程同步的,暂停当前线程,等待子线程的执行,也称之为线程合并,join方法特点将并行执行的事情合并为串行执行。执行的本质是使用线程间通信机制来完成线程同步的。
※注意点:
- 有两个线程:thread1和thread2;thread2在thread1中调用join()方法,此时thread1会暂停,等thread2执行完以后才会执行,注意先后顺序。
public class thread1 extends Thread{ public static void main(String[] args) { ... thread2.join(); ... } }
interrupt()方法
附源代码:
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0();
}
private native void interrupt0();
interrupt()是一个普通方法,由对象调用,该对象的线程会进行线程中断,主要用于会抛出InterruptedException的方法:如:slee(),join(),wait()等。
※方法特点:
- 如果线程当前是可中断的阻塞状态(调用sleep、join、wait等方法会导致线程进入到阻塞状态:WAITING/TIMED_WAITING/BLOCKED),此时会抛出InterruptedException,退出阻塞状态。
- interrupt()方法不会对正在运行的线程进行中断,直到发生了阻塞后,立即抛出异常,退出阻塞状态。
线程的分类
守护线程
守护线程:也称之为“后台线程”,服务于用户线程,通常用来执行后台任务。如:垃圾回收线程。
守护线程的生命周期:守护线程的生命周期是依赖于用户线程,当用户线程存在,守护线程就会存活,当用户线程生命终止,守护线程的也会随之消亡。
方法
//设置守护线程,默认为FALSE:非守护线程
public final void setDaemon(boolean on) {
checkAccess();
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
//判断是否为守护线程,FALSE为非守护线程
public final boolean isDaemon() {
return daemon;
}
用户线程
用户线程:指不需要内核支持而在用户程序中实现的线程。
用户线程生命周期:主程序结束后,用户线程还会继续执行。
线程优先级
线程优先级:指线程执行的先后顺序。
优先级特点:
- java线程的优先级并不绝对,它所控制的是执行的优先机会而不是优先的顺序,优先级的决定权在操作系统,java设置的优先级只是被优先执行的概率要高,但不绝对。
- java中优先级共有10级,分为1-10,数值越大,表明优先级越高,一般普通的线程优先级是5。
//最小优先级 public final static int MIN_PRIORITY = 1; //普通优先级 public final static int NORM_PRIORITY = 5; //最大优先级 public final static int MAX_PRIORITY = 10;
- 优先级具有继承性,如果一个线程B在另一个线程A中创建出来,那么线程B的优先级和线程A保持一致。
方法
//设置优先级
public final void setPriority(int newPriority){}
//获取优先级
public final int getPriority() {return priority;}
关于多线程的有关内容,详戳【Java多线程】,有关上面提到的线程状态,详戳【Java线程的状态及转换】。更多Java内容,详戳主页。