铁锤的IT奇妙探险 Java Back-End Coder

线程中的常用方法

2020-07-03


并发编程是程序开发过程中必定会遇到的“拦路虎”,一旦扎实地啃下了这块硬骨头,面试官便会对你青睐,所以加油吧少年!

线程

线程的状态

线程的状态以枚举的方式定义在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();
}

  1. start()属于Thread自身的方法,并且是线程安全的;run()为Runnable的抽象方法,必须重写该方法。
  2. start()用来开启多线程,run()只是包含业务的普通方法。
  3. 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进行了判断:

  1. 也就是当nanos大于等于500微秒时,millis就加1.当nanos小于500微秒时,不改变millis的值.
  2. 当millis的值为0时,只要nanos不为0,就将millis设置为1.所以nanos的功能类似于四舍五入。
  3. 该方法与sleep(mills)的效果几乎一致
  4. sleep()让当前方法休眠指定时间,但它不释放锁

Similar Posts

Comments