黑马程序员--04.多线程--02.【run()和start()】【线程的运行状态】【获取想成对象及其名称】

来源:互联网 发布:win10默认网卡mac地址 编辑:程序博客网 时间:2024/05/20 00:17

多线程--2

      run()和start()  线程的运行状态 获取线程对象以及名称

----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------

1.    run()和start()关系

1). Thread类的run()方法

(1).Thread子类一定要覆盖父类run()方法的原因

[1]. Thread类的run()的作用:用于存储非主线程线程代码

[2]. 子类重写run方法目的:将需要自定义线程运行代码存放在run()方法中,等待自定义启动之后,运行run()中的内容。

(2). 主线程直接调用线程子类的run()方法的结果

如果主线程仅仅调用子类的run()方法的结果就是主线程直接执行线程子类的run()方法的代码,没有启动另一个进程/程序控制单元整个程序/进程仍然是单线程执行。

2). Thread类的start()方法

(1). 主线程中要调用start()方法而不是调用run()方法的原因

[1]. Thread类的start()的作用:用于开启线程执行自定义在run()代码

[2]. 主线程必须调用线程实例的start()原因:调用run()之后,成个程序仍然是单线程、调用start()方法之后,start中的本地native方法start0()方法会调用操作系统的底层的资源创建相关的线程。这个时候,这个的进程才是多个线程来执行。

(2). start()的相关知识点

[1]. 主线程调用某个线程对象的start()之后,这个线程一定会马上执行么

不一定!!!!!!!!

因为CPU在某一个时刻仅仅能执行一个进程中的一个线程进程中其余的线程都处于临时阻塞状态,处于运行状态都在等待获取CPU的执行权

2.    线程运行状态转换

1). 线程运行状态转换图


2). 各种状态的转换关系

(1). 调用start()方法

调用start()方法会使得线程从新建状态发生状态跳转。最有可能跳转到临时阻塞状态,同时也有很小的可能使得该线程立刻被执行,处于运行状态

因为运行在一个进程中的线程有很多,但是一个时刻只能有一个线程被CPU执行。所以,只有很小的可能这个线程会抢到CPU的执行权。很大的可能性这个线程处于等待获取CPU执行权的状态,这就是该线程处于临时阻塞状态。

(2). 调用sleep(时间)方法或者wait()方法

线程如果碰到sleep(时间)方法或者wait()方法,就会立刻变成冻结状态放弃CPU的执行权。

(3). sleep()运行时间到或者调用notify()方法

sleep()运行时间到或者调用了notify()方法,处于冻结状态的线程会激活很有可能跳转到临时阻塞状态。有很小的可能回到运行状态

(4). stop()或者run()方法运行完成

当调用stop()方法或者run()方法被线程运行完成,线程就从运行状态走向了消亡状态。

(5). 临时阻塞状态和运行状态

这两个状态之间的转换完全是看相应的线程有没有CPU执行权如果有,就执行没有,就等待。

【总结】临时阻塞状态是非常重要的!!!!!除了线程的被创建的状态消亡状态之外,运行状态冻结状态都是临时阻塞状态有紧密联系的。

【注意】被创建的状态消亡状态不可逆转性

       {1}.不能其他状态回到被创建的状态

       {2}. 不能消亡状态回到其他状态

3). 具有CPU执行资格和具有CPU执行权

递进关系:只有具备CPU执行资格线程才能谈是否具有CPU执行权

 

是否具有CPU执行资格

是否具有CPU执行权

 运行状态【双有】

冻结状态【双无】

----

临时阻塞状态【一有一无】

【注意】有的地方又把冻结状态分成睡眠状态等待状态

3.    获取线程对象以及线程对象的名称

(1). Thread类的源码开始

public

class Thread implementsRunnable {

    /* Make sure registerNatives isthe first thing <clinit> does. */

    private static native void registerNatives();

    static {

       registerNatives();

    }

private char name[];

}

(1). 线程对象的name属性

[1].每一个线程都有自己的名字。所以在Thread类中,有一个非静态的成员变量:字符数组name[];。这样,就有对应的setter和getter来访问这个表示线程名称的属性。

[2]. 默认线程的名称Thread-编号”(编号从0开始

(2). 获取线程的名称 ---name的getter

[1]. 获取线程对象的名字就是用Thread类的getName()方法即可

[2]. Thread类的getName()的源码:

public final String getName(){

    return String.valueOf(name);

}

(3). 设置Thread类对象的名称

[1]. 通过构造函数初始化方式为线程对象设置对应的线程名称

{1}. Thread类的空参构造函数源码

public Thread() {

init(null, null, "Thread-" + nextThreadNum(), 0);

//黄色背景是默认初始化名称

}

{2}. Thread类的String列表的构造函数

public Thread(String name) {

    init(null,null,name, 0);  //黄色背景是用户传如的线程的名字

}

[2]. 通过name属性settersetName()方法为线程改变线程名称

public final void setName(String name) {

    checkAccess();

    this.name = name.toCharArray();

}

【总结】改变一个对象的某个私有属性一般有两种方式

初始化的时候改变 ----构造函数

任意时刻改变 ----属性的getter

(4). 获取当前被CPU执行的线程对象

[1]. 通过Thread类的静态方法 currentThread()方法来获取。

[2]. 源码:public static native ThreadcurrentThread();

这个方法是本地化方法。

[3]. currentThread()方法的用处

{1}. run()方法Thread.currentThread()返回值就是this变量

{2}. run()方法以外,Thread.currentThread()获取当前被执行的线程

----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------

 

原创粉丝点击