并发编程是程序开发过程中必定会遇到的“拦路虎”,一旦扎实地啃下了这块硬骨头,面试官便会对你青睐,所以加油吧少年!
线程
线程的状态
线程的状态以枚举的方式定义在Thread中,共包含六个状态:NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED.
BLOCKED和WAITING
BLOCKED 可以理解为当前线程还处于活跃状态,只是在阻塞等待其他线程使用完某个锁资源;而WAITING则是因为自身调用了 Object.wait() 或着是Thread.join()而进入等待状态,只能等待其他线程执行Object.notify() 或 Object.notifyAll() 才能被唤醒.
start()和run()
public synchronized void start() {
// 状态验证,不等于 NEW 的状态会抛出异常
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) {
// 不处理任何异常,如果 start0 抛出异常,则它将被传递到调用堆栈上
}
}
}
public class Thread implements Runnable {
// 忽略其他方法......
private Runnable target;
@Override
public void run() {
if (target != null) {
target.run();
}
}
}
FunctionalInterface
public interface Runnable {
public abstract void run();
}
- start()属于Thread自身的方法,并且是线程安全的;run()为Runnable的抽象方法,必须重写该方法。
- start()用来开启多线程,run()只是包含业务的普通方法。
- start()只能调用一次,run()可以多次调用
线程优先级
// 线程可以拥有的最小优先级
public final static int MIN_PRIORITY = 1;
// 线程默认优先级
public final static int NORM_PRIORITY = 5;
// 线程可以拥有的最大优先级
public final static int MAX_PRIORITY = 10
优先级更高的优先执行概率更大,但不能保证一定先执行。我们可以通过Thread.setPriority()设置优先级。
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
// 先验证优先级的合理性
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
// 优先级如果超过线程组的最高优先级,则把优先级设置为线程组的最高优先级
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
常用方法
join()
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
// 超时时间不能小于 0
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
// 等于 0 表示无限等待,直到线程执行完为之
if (millis == 0) {
// 判断子线程 (其他线程) 为活跃线程,则一直等待
while (isAlive()) {
wait(0);
}
} else {
// 循环判断
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
在线程中调用join()后,执行权让出,若参数为0,则会一直等待其他线程执行完毕,参数大于0 时,过了时间之后会继续执行当前线程。join()底层还是通过wait()来实现的。
sleep()
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");
}
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
sleep(millis);
}
方法对传入的nanos进行了判断:
- 也就是当nanos大于等于500微秒时,millis就加1.当nanos小于500微秒时,不改变millis的值.
- 当millis的值为0时,只要nanos不为0,就将millis设置为1.所以nanos的功能类似于四舍五入。
- 该方法与sleep(mills)的效果几乎一致
- sleep()让当前方法休眠指定时间,但它不释放锁