线程(二)——线程的状态及常用方法

一.线程的状态


 1.新建状态(New):
  当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
 2.就绪状态(Runnable):
  当调用线程对象的start()方法,线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
  另外,start()方法是让线程进入就绪状态,而run()方法只是一个普通方法,当线程进入运行状态的时候会执行线程的run()方法。

public class TestRunAndStart {
    public static void main(String[] args) {
        new Thread("线程一") {
            @Override
            public void run() {
                super.run();
                System.out.println("当前运行的线程为:"Thread.currentThread().getName());
            }
        }.start();
        new Thread("线程二") {
            @Override
            public void run() {
                super.run();
                System.out.println("当前运行的线程为:"Thread.currentThread().getName());
            }
        }.run();
    }
}

  运行结果:

当前运行的线程为:线程一
当前运行的线程为:main

 3.运行状态(Running):
  当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。
  注:就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
 4.阻塞状态(Blocked):
  处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
  (1).等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
  (2).同步阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
  (3).其他阻塞:通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
 5.死亡状态(Dead):
  线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

二.线程类的常用方法

 1.构造方法

方法作用
Thread()创建新的线程对象,该线程默认名称为自动生成,形式为 “Thread-“+n ,其中的 n 为整数。
该方法通常用于创建匿名内部类并重写 run() 方法。
Thread(Runnable target)创建新的线程对象, target 对象为该新线程对象 run() 方法被调用的对象。
Thread(String name)创建新的线程对象, name 为该线程的名称。
Thread(ThreadGroup group,Runnable target)创建新的线程对象, group 为该线程所属的线程组。target 对象为该新线程对象 run() 方法被调用的对象。
Thread(ThreadGroup group,Runnable target,String name,long stackSize)创建新的线程对象,group 为该线程所属的线程组, target 对象为该新线程对象 run() 方法被调用的对象, name 为该线程的名称, stackSize 新线程的预期堆栈大小,为零时表示忽略该参数。
stackSize 参数(如果有)的作用具有高度的平台依赖性,在某些平台上, stackSize 参数的值无论如何不会起任何作用。通常建议,可以让虚拟机自由处理 stackSize 参数。

(1).Thread()

public void emptyConstitution(){
    new Thread(){
        @Override
        public void run() {
            System.out.println("新线程执行");
        }
    }.start();
}

  控制台输出

新线程执行

(2).Thread(Runnable target)

public void runnableConstitution(){
    new Thread(new Runnable() {
        public void run() {
            System.out.println("新的runnable方法");
        }
    }).start();
}

  控制台输出

新的runnable方法

(3).Thread(String name)

public void nameConstitution(){
    new Thread("MyThread"){
        @Override
        public void run() {
            System.out.println("新的线程名为:"+this.getName());
        }
    }.start();
}

  控制台输出

新的线程名为:MyThread

 2.静态方法

方法返回值类型作用
currentThread()Thread返回对当前正在执行的线程对象的引用。
holdsLock(Object obj)boolean当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true 。
sleep(long millis)void在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
sleep(long millis, int nanos)void在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
yield()void暂停当前正在执行的线程对象,并执行其他线程。
setDefaultUncaughtExceptionHandler
(UncaughtExceptionHandler eh)
void设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。

(1).holdsLock(Object obj)

@Test
public void static_HoldsLock() {
    Object lock = new Object();
    synchronized (lock) {
        System.out.println("synchronized代码块中:" + Thread.holdsLock(lock));
    }
    System.out.println("synchronized代码块外:" + Thread.holdsLock(lock));
}

  控制台输出

synchronized代码块中:true
synchronized代码块外:false

(2).sleep(Object obj)

@Test
public void static_sleep() throws InterruptedException {
    long start = System.currentTimeMillis();
    Thread.sleep(1000);
    long end = System.currentTimeMillis();
    System.out.println("线程休眠了" + (end - start) + "毫秒");
}

  控制台输出

线程休眠了1001毫秒

(3).yield()

//该变量为共享变量,volatile关键字保证了线程间的可见性
private volatile boolean static_Yield_Flag = false;

@Test
public void static_Yield() {
    new Thread("新线程") {
        @Override
        public void run() {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            static_Yield_Flag = true;
            System.out.println("isContinue状态修改为:ture");
            System.out.println(Thread.currentThread().getName() + "结束");
        }
    }.start();
    while (!static_Yield_Flag) {
        Thread.yield();
    }
    System.out.println("主线程结束");
}

  控制台输出

isContinue状态修改为:ture
新线程结束
主线程结束

(4).setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh)

@Test
public void static_SetDefaultUncaughtExceptionHandler() {
    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
        public void uncaughtException(Thread t, Throwable e) {
           System.out.println(t.getName()+"线程使用了全局异常处理器,异常信息:" + e.getMessage());
        }
    });
    new Thread("新线程") {
        @Override
        public void run() {
            System.out.println(1 / 0);//可以调用全局UncaughtExceptionHandler
        }
    }.start();
    System.out.println("抛异常前");
    //没有局部UncaughtExceptionHandler,返回当前ThreadGroup
    System.out.println(Thread.currentThread().getUncaughtExceptionHandler());
    throw new RuntimeException("抛异常");
}

  控制台输出

抛异常前
java.lang.ThreadGroup[name=main,maxpri=10]
全局:/ by zero

java.lang.RuntimeException: 抛异常

    at com.xin.thread.demo04_threadMethod._Main_ThreadMethodTest.static_SetDefaultUncaughtExceptionHandler(_Main_ThreadMethodTest.java:80)
    ......

  在JUnit测试时主线程抛的异常不会走全局的UncaughtExceptionHandler(未知原因),而新创建的线程则会走全局UncaughtExceptionHandler。
  然而在main方法调用时主线程抛的异常不能走UncaughtExceptionHandler,估计应该与JUnit内部实现有关(未看过JUnit源码不好下定论)。

 3.实例方法

方法返回值类型作用
getId()long返回该线程的标识符。
getName()String返回该线程的名称。
setName(String name)void改变线程名称,使之与参数 name 相同。
getPriority()int返回线程的优先级。
setPriority(int newPriority)void更改线程的优先级。参数newPriority应大于等于1,小于等于10,否则会抛出IllegalArgumentException
getState()Thread.State返回该线程的状态。 该方法用于监视系统状态,不用于同步控制。
getThreadGroup()ThreadGroup返回该线程所属的线程组。
isAlive()boolean测试线程是否处于活动状态。
isDaemon()boolean测试该线程是否为守护线程。
setDaemon(boolean on)void将该线程标记为守护线程或用户线程。

(1).getState()

@Test
public void getState() throws InterruptedException {
    Thread t = new Thread("新线程") {
        @Override
        public void run() {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getName() + "完成");
        }
    };
    System.out.println("创建后状态为:" + t.getState());
    t.start();
    System.out.println("调用start()方法后状态为:" + t.getState());
    Thread.sleep(50);
    System.out.println("调用sleep()方法后状态为:" + t.getState());
    Thread.sleep(150);
    if (!t.isAlive()) {
        System.out.println("线程方法后状态为:" + t.getState());
    }
}

  控制台输出

创建后状态为:NEW
调用start()方法后状态为:RUNNABLE
调用sleep()方法后状态为:TIMED_WAITING
新线程完成
线程方法后状态为:TERMINATED

(2).isAlive()

@Test
public void isAlive() throws InterruptedException {
    Thread t = new Thread("新线程") {
        @Override
        public void run() {
            System.out.println(getName() + "结束");
        }
    };
    System.out.println(t.isAlive());
    t.start();
    System.out.println(t.isAlive());
    Thread.sleep(100);
    System.out.println(t.isAlive());
}

  控制台输出

false
true
新线程结束
false

(3).setDaemon()

@Test
public void setDaemon() throws InterruptedException {
    Thread t = new Thread("新线程") {
        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(getName() + "运行中");
            }
        }
    };
    t.setDaemon(true);
    t.start();
    System.out.println(t.getName() + "为守护线程:" + t.isDaemon());
    Thread.sleep(500);
}

  控制台输出

新线程为守护线程:true
新线程运行中
新线程运行中
新线程运行中
新线程运行中

  守护线程又叫后台线程,最常见的守护线程就是垃圾回收线程。当程序中所有正在运行中的线程都是守护线程时,程序就会退出(守护线程也会结束运行);而只要有一条还在运行的线程为用户线程(即非守护线程),则守护线程将会继续运行。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值