线程的生命周期大致分为五种状态:
新建一个线程对象。
启动线程,调用start方法或者调用线程池的excute方法等,此时线程会进入可运行线程池中,等待获取CPU的时间片。
运行状态,也就是获得了CPU的时间片,执行run方法
阻塞状态,线程因为某种原因让出了CPU的时间片,暂时停止运行。阻塞可能是调用了wait方法,I/O阻塞,同步锁阻塞等。当再次获取到CPU的时间片,就会重新进入运行状态
线程运行结束,就是方法执行结束,或者是main主线程结束了,也会导致线程进入dead,结束生命周期
public class TheadTest implements Runnable {
@Override
public void run(){
System.out.println(Thread.currentThread().getName()+ "进入创建的线程");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "新线程暂停了1秒钟");
}
}
上面是一个实现了runable的类,现在对一些常用的方法熟悉一下。
TheadTest test1 = new TheadTest();
TheadTest test2 = new TheadTest();
Thread thread1 = new Thread(test1,"线程1"); //新建状态
Thread thread2 = new Thread(test2,"线程2"); //新建状态
thread1.start(); //可运行状态
thread2.start(); //可运行状态
try {
thread1.join(1500); //main线程等待thread1执行1.5秒后执行
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程结束");
输出结果:
线程1进入创建的线程
线程2进入创建的线程
线程2新线程暂停了1秒钟
线程1新线程暂停了1秒钟
主线程结束
如果没有thread1.join(1500)这一行,“主线程结束”会先输出。
join方法是使得当前线程等待指定线程执行完或者等待一点时间内后进入可运行状态,所以这里main线程等待了1.5s才进入到可运行状态,获取到CPU的时间片,这时线程1和线程2已经执行完毕。
这个方法是让当前线程暂停指定的时间,
join和sleep都是让线程从运行状态进入阻塞状态,指定时间后,重新进入可运行状态,与其他线程抢占CPU的时间片。
yeid方法是把当前线程从运行状态转为可运行状态,把运行机会让给相同优先级的其它线程;
代码如下:
public class TheadTest implements Runnable {
@Override
public void run(){
for(int i = 0;i<5;i++){
System.out.println(Thread.currentThread().getName()+" : "+ i);
//Thread.yield();
}
}
}
public static void main(String[] args) {
TheadTest test1 = new TheadTest();
TheadTest test2 = new TheadTest();
Thread thread1 = new Thread(test1,"线程1"); //新建状态
Thread thread2 = new Thread(test2,"线程2"); //新建状态
thread1.start(); //可运行状态
thread2.start(); //可运行状态
System.out.println("主线程结束");
}
没有调用yeid方法,输出为:
主线程结束
线程1 : 0
线程1 : 1
线程2 : 0
线程1 : 2
线程1 : 3
线程2 : 1
线程1 : 4
线程2 : 2
线程2 : 3
线程2 : 4
如果把注释去掉,执行yeid方法,输出为:
主线程结束
线程1 : 0
线程2 : 0
线程2 : 1
线程1 : 1
线程1 : 2
线程2 : 2
线程2 : 3
线程1 : 3
线程2 : 4
线程1 : 4
这个只是其中一次的结果,每一个结果都可能不同,但是可以看出执行了yeid方法和不执行的区别
join是让当前线程从运行状态进入阻塞状态,让其它线程执行,yeid方法是让当前线程从运行状态进入可运行状态,把机会让给其它相同优先级的线程,所以yeid并不能保证当前线程在下一个争抢当中抢不到时间片,有可能执行了yeid,但是下一个还是抢到了。
getName :获取线程名字,可以在构造参数设置,不设置会默认设置线程名字,Thread-1一类的名字
getState :获取线程状态,就是上面的几个生命周期状态,
isAlive:获取线程是否死亡;
TheadTest test1 = new TheadTest();
TheadTest test2 = new TheadTest();
Thread thread1 = new Thread(test1,"线程1"); //新建状态
Thread thread2 = new Thread(test2,"线程2"); //新建状态
thread2.setPriority(1);
thread1.setPriority(10);
thread1.start(); //可运行状态
thread2.start(); //可运行状态
System.out.println("主线程结束");
setPriority方法是设置线程的优先级,优先级从1-10,数字越大的优先级也越大,这里设置thread1的优先级为10,thread2的优先级为1,所以thread1抢先抢到CPU的时间片的概率更大,注意:优先级越大只是抢到的概率更大,并不代表一定会抢到;
/**
* The minimum priority that a thread can have.
*/
public static final int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public static final int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public static final int MAX_PRIORITY = 10;
以上是Thread内部定义的三个优先级的常量,分别对应着1,5,10;
因为优先级只是增加概率,所以不可太过依赖于优先级设置;
守护线程就是作为线程的守护角色,当主线程dead的守护,守护线程会被强行结束;
TheadTest test1 = new TheadTest();
Thread thread1 = new Thread(test1,"线程1"); //新建状态
thread1.setDaemon(false);
thread1.start(); //可运行状态
System.out.println("主线程结束");
setDeamon就是设置守护线程,false代表不设置为守护线程。输出为:
主线程结束
线程1进入创建的线程
线程1新线程暂停了1秒钟
如果把代码改成: thread1.setDaemon(true);
输出是:
主线程结束
这是也mai线程已经结束了任务,出栈了,所以守护现象thread1也会被强行结束,run方法里面的打印就没有输出;