ThreadAPI详解

ThreadAPI详解

线程休眠(sleep)

  • sleep方法
public static void sleep(long milis) throws InterruptedException
public static void sleep(long milis,int nanos) throws InterruptedExceptionInterruptedException
  • sleep方法会使当前线程进入指定毫秒数的休眠,暂停执行,最终以系统的定时器和调度器的精度为准。
  • 每个线程休眠都互不影响,Thread.sleep只会导致当前线程进入指定时间的休眠
  • 休眠不会放弃monitor锁的所有权
  • 在实现线程休眠的时候推荐使用枚举TimeUnit
  • 示例:
//线程休眠3小时24分17秒88毫秒(一秒等于1000毫秒)
Thread.sleep(12257088L)
TimeUnit:
TimeUnit.HOURS.sleep(3);
TimeUnit.MINUTES.sleep(3);
TimeUnit.SECONDS.sleep(3);
TimeUnit.MILLISECONDS.sleep(3);
  • 好处:对sleep提供了很好的封装,不必去做时间单位的换算

线程yield

  • yield方法属于一种启发式的方法,会提醒调度器线程愿意放弃当前CPU资源,如果CPU资源不紧张(即没有其他线程使用抢占CPU),则会忽略提醒。
  • 该方法会使得线程从Running状态切换到Runnable状态,方法不常用,不会主动放弃执行
  • 就算线程调用yield方法,也有可能线程依旧执行,当CPU资源充足的时候

sleep与yield对比

  1. yield实际上是调用了sleep(0)
  2. sleep会导致当前线程暂停指定的事件,没有CPU时间片的消耗
  3. yield只是对CPU调度器的一个提示,如果CPU调度器没有忽略这个提示,它会导致线程上下文的切换
  4. sleep会使线程短暂block,会在给定的事件内释放CPU资源
  5. yield会使Running状态的Thread进入Runnable状态(如果CPU调度器没有忽略这个提示的话)
  6. sleep几乎百分之百的完成给定时间的休眠,而yield的提示不一定成功
  7. 一个线程sleep另一个线程调用interrupt会捕获到中断信号,而yield则不会

线程的优先级设置

  • 方法:
public final void setPriority(int newPriority);//为线程设定优先级
public final void getPriority();//获取线程优先级
  • 进程有优先级,同样线程也有,优先级的设置同样是一个提示操作(hint),
  • 对于root用户,它会hint操作系统所设置的优先级别,否则会被忽略
  • 当CPU忙时,设置优先级的优先级的会获取更多的CPU时间片,闲时优先级设置不产生作用
  • 注意:不要让某些业务严重的依赖线程的优先级别,一般使用线程的默认优先级就行了,默认优先级为5

获取线程ID

public long getId();//获取线程的唯一ID,线程的ID在整个JVM进程中都是唯一的

获取当前线程

public static Thread currentThread()//用于返回当前执行线程的引用

设置线程上下文类加载器

/*获取线程上下文的类加载器,如果没有修改线程上下文类加载器的情况下,
则保持与父线程同样的类加载器*/
public ClassLoader getContextClassLoader();

//设置线程的类加载器,打破Java类加载器的父委托机智
public void setContextClassLoader(ClassLoader classLoader)

线程interrupt(较为重要)

Interrupt

  • 线程interrupt是一个常用的重要API
  • interrupt 相关API
public void interrupt();
public static boolean interrupted();
public boolean isInterrupted();
  • 使得线程进入阻塞状态的方法:
Object.wait();
Object.wait(long);
Object.wait(long,int);
Thread.sleeo(long);
Thread.sleeo(long,int);
Thread.join();
Thread.join(long);
Thread.join(long,int);
//InterruptibleChannel的IO操作
//Selector的wakeup()方法
//其他导致阻塞的方法
  • 如果一个线程调用被阻塞线程的interrupt方法,则会打断阻塞,所以方法可被称为可中断方法
  • 打断一个线程并不等于该线程的生命周期结束,只是打断了当前线程的阻塞状态
  • 一旦线程被打断,就会抛出一个InterruptedException的异常,是一个信号通知当前线程被打断
  • 死亡状态的线程调用interrupt是无效的

isInterrupted

-isInterrupted是Thread的一个成员方法,主要判断当前线程是否被中断,只是对interrupt标识的一个判断,不会影响标识

interrupted

  • 是一个静态方法,也是用于判断当前线程是否被中断,调用该方法会擦出掉线程的interrupt标识
  • 注意:当前线程被打断,那么调用interrupted会返回true,并且擦除掉interrupt标识,变成false,之后在调用永远返回的都是false

Thread的Join方法

  • 接口:
public final void join()throws InterruptedExcption
public final synchronized void join(long millis)throws InterruptedExcption
public final synchronized void join(long millis,int nanos)throws InterruptedExcption
  • 作用:使得线程进入阻塞状态,和sleep相同都是可中断方法。
  • 示例:
    • 有一个线程B,调用线程B的join()方法,则当前线程进入阻塞状态,知道线程B结束,A线程才能就是进入Runnable状态
    • 主线程创建子线程,子线程调用join方法,只有子线程运行结束,主线程才能执行。

stop方法关闭一个Thread

  • stop方法已经被移除,该方法关闭线程时可能不会释放掉monitor的锁
@Deprecated
public final void stop();

正常关闭线程

  • 线程完成任务后正常结束生命。
  • 在new Thread时,派生成本较高,因此线程往往会循环的执行某个任务,如心跳检查等。线程退出,需要借助中断线程的方式,通过try-catch捕获InterruptException异常来中断线程。
    • 示例:
public class InterruptThreadTest {
   public static void main(String[] args) throws InterruptedException{
       Thread thread = new Thread(){
           @Override
           public void run() {
               super.run();
               System.out.println("start work!");
               System.out.println(isInterrupted());
               while (isInterrupted() == false)
               {
                   interrupt();
                   System.out.println(isInterrupted());
                   try {
                       TimeUnit.SECONDS.sleep(50);
                   } catch (Exception e){
                       e.printStackTrace();
                   }
                   System.out.println(interrupted());
                   System.out.println(isInterrupted());
                   //working
               }
               System.out.println("i will be exiting!");
           }
       };
       thread.start();
       TimeUnit.SECONDS.sleep(1);
       System.out.println("System will be shutDown.");
       thread.interrupt();
   }
}
  • 使用volatile开关控制
  • interrupt方式存在标识被擦除或逻辑单元中不会调用任何可中断方法
  • 使用volatile修饰的开关flag关闭线程也可完成关闭线程
import java.util.concurrent.TimeUnit;
public class VolatileThreadTest {

    static class MyTask extends Thread{
        private volatile boolean closed = false;
        @Override
        public void run() {
            super.run();
            System.out.println("I will start work");
            while (!closed && !isInterrupted()){


            }
            System.out.println("I will be exiting");
        }

        public void close(){
            this.closed = true;
            this.interrupt();
        }
    }
    public static void main(String[] args) throws InterruptedException{
        MyTask task = new MyTask();
        task.start();
        TimeUnit.MINUTES.sleep(1);
        System.out.println("System will ben shutdown");
        task.close();
    }
}

异常退出

  • 在一个线程的执行单元中,不允许抛出checked异常的,如果线程在运行中需要捕获checked异常并且判断是否还有运行下去的必要,那么此时可将checked异常封装成unchecked异常(RuntimeException)抛出进而结束线程的生命周期

进程假死

  • 线程假死,就是线程虽然存在,但没有日志输出,程序不进行任何的作业,看起来像死了一样,事实上已经死了,原因就是某个线程阻塞了或线程出现了死锁的情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值