1 .Thread中重要的属性

 publicclass Thread implements Runnable { //继承自Runnable接口private char    name[];   // 以char数组保存线程的名字
private int priority; // 线程优先级别
/* Whether or not the thread is a daemon thread. */
private boolean daemon = false; //是否为守护线程
/* What will be run. */
private Runnable target; //构造方法中传递一个Runnable对象 最终由target指向 /* The group of this thread */
private ThreadGroup group; //线程组 //预先定义好的优先级
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10; // 这个类是在ThreadLocal中定义 类似于Map的key-value的数据结构(后面会有该类的叙述)
// 特殊之处:key的值是固定的 就是当前线程
ThreadLocal.ThreadLocalMap threadLocals = null; // 当不为线程命名的时候 默认名称是Thread-编号 编号从0开始增长 就是依靠这个 前面已经详细讲述
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
27 ... ...
}

2 构造方法

在Thread重载了很多构造方法 我们挑选几个常用的进行列举

   public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
} public Thread(String name) {
init(null, null, name, 0);
} public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
} public Thread(Runnable target, String name) {
init(null, target, name, 0);
}

可以看出Thread的构造方法最终都会调用init方法

   //4个参数分别表示 线程所属组 Runnable对象  线程名字 线程栈大小
//一般只会用到第2、3个参数
private void init(ThreadGroup g, Runnable target, String name, long stackSize) { Thread parent = currentThread(); //获取当前运行的线程为父线程 一些属性将会基础自parent
SecurityManager security = System.getSecurityManager();
if (g == null) {
if (security != null) {
g = security.getThreadGroup();
}
if (g == null) {
g = parent.getThreadGroup();
}
}
g.checkAccess(); if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted(); this.group = g; //指定要开启线程的组
this.daemon = parent.isDaemon();//指定要开启线程是否为守护线程 来自于parent
this.priority = parent.getPriority();//设置优先级的值 来自于parent
this.name = name.toCharArray();//设置线程名字
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext = AccessController.getContext();
this.target = target;//设置要执行的目标 Runnable对象
setPriority(priority);//设置优先级
if (parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize; /* Set thread ID */
tid = nextThreadID(); this.me = this;
}

3 线程的状态

 /* Java thread status for tools,
* initialized to indicate thread 'not yet started'
*/
private int threadStatus = 0; //描述线程状态的属性

线程有四种状态

  1. 新状态:线程已被创建但尚未执行(start() 尚未被调用)。

  2. 可执行状态:线程可以执行,虽然不一定正在执行。CPU 时间随时可能被分配给该线程,从而使得它执行。

  3. 死亡状态:正常情况下 run() 返回使得线程死亡。调用 stop()或 destroy() 亦有同样效果,但是不被推荐,前者会产生异常,后者是强制终止,不会释放锁。

  4. 阻塞状态:线程不会被分配 CPU 时间,无法执行。

这些状态 Thread中是以枚举来描述的:

     public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}

Thread中的不同方法的执行 会使线程进入不同的状态 如图:

将blocked、waiting、time waiting统称为阻塞状态,这个也是可以的

只不过这里我想将线程的状态和Java中的方法调用联系起来,所以将waiting和time waiting两个状态分离出来。

4 Thread中的成员方法

1)start方法

  start()用来启动一个线程,当调用start方法后,系统才会开启一个新的线程来执行用户定义的子任务,在这个过程中,会为相应的线程分配需要的资源。

一个线程只能start 1次  以为一个只需要分配一次资源就够了  如果启动多次 就会出错:非法的线程状态异常 IllegalThreadStateException

     public synchronized void start() {
if (threadStatus != 0 || this != me) //只有处于未开启状态的线程才可以继续执行
throw new IllegalThreadStateException();
group.add(this);
start0();
if (stopBeforeStart) {
stop0(throwableFromStop);
}
} private native void start0();
private native void stop0(Object o);

2)run方法

run()方法是不需要用户来调用的,当通过start方法启动一个线程之后,当线程获得了CPU执行时间,便进入run方法体去执行具体的任务。

注意,继承Thread类必须重写run方法,在run方法中定义具体要执行的任务。

如果我们覆盖了run方法 就会执行我们覆盖的方法

如果我们向Thread传递了一个Runnable对象 就会执行该对象的run方法

 public void run() {
if (target != null) { //判断是否有Runnable对象传入
target.run();
}
}

那么请思考下面程序的输出:

     public static void main(String[] args) {
new Thread(new Runnable() { @Override
public void run() {
System.out.println("run in Runnable");
} }) {
public void run() {
System.out.println("run in Thread");
}
}.start();
}

答案:run in Thread

这就表明既复写run方法又传递Runnable时执行的是覆盖的方法

因为执行原有的run方法已经失效  根本不会判断if (target != null)  更不会执行target.run();

3)sleep方法

sleep方法有两个重载版本:

sleep(long millis)     //参数为毫秒

sleep(long millis,int nanoseconds)    //第一参数为毫秒,第二个参数为纳秒

sleep相当于让线程睡眠,交出CPU,让CPU去执行其他的任务。

但是有一点要非常注意,sleep方法不会释放锁,也就是说如果当前线程持有对某个对象的锁,则即使调用sleep方法,其他线程也无法访问这个对象。

注意,如果调用了sleep方法,必须捕获InterruptedException异常或者将该异常向上层抛出。

当线程睡眠时间满后,不一定会立即得到执行,因为此时可能CPU正在执行其他的任务。所以说调用sleep方法相当于让线程进入阻塞状态。

4)yield方法

调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会释放锁。

但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会。

注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。

5)join方法join方法有三个重载版本:

join()

join(long millis)     //参数为毫秒

join(long millis,int nanoseconds)    //第一参数为毫秒,第二个参数为纳秒

假如在main线程中,调用thread.join方法,则main方法会等待thread线程执行完毕或者等待一定的时间。

如果调用的是无参join方法,则等待thread执行完毕,如果调用的是指定了时间参数的join方法,则等待一定的时间。

6)interrupt方法

interrupt,顾名思义,即中断的意思。单独调用interrupt方法可以使得处于阻塞状态的线程抛出一个异常,

也就说,它可以用来中断一个正处于阻塞状态的线程直接调用interrupt方法不能中断正在运行中的线程;另外,通过interrupt方法和isInterrupted()方法来停止正在运行的线程。

但是一般情况下不建议通过这种方式来中断线程,一般会在MyThread类中增加一个属性 isStop来标志是否结束while循环,然后再在while循环中判断isStop的值。 

那么就可以在外面通过调用setStop方法来终止while循环。

 class MyThread extends Thread{

         private volatile boolean isStop = false;

         public void run() {
int i = 0;
while(!isStop){
i++;
}
} public void setStop(boolean stop){
this.isStop = stop; }
}

7)stop方法

stop方法已经是一个废弃的方法,它是一个不安全的方法。

因为调用stop方法会直接终止run方法的调用,并且会抛出一个ThreadDeath错误,如果线程持有某个对象锁的话,会完全释放锁,导致对象状态不一致。所以stop方法基本是不会被用到的。

8)destroy方法destroy方法也是废弃的方法。基本不会被使用到。

9)以下是关系到线程属性的几个方法:

  1)getId  用来得到线程ID

  2)getName和setName       用来得到或者设置线程名称。

  3)getPriority和setPriority   用来获取和设置线程优先级。

  4)setDaemon和isDaemon  用来设置线程是否成为守护线程和判断线程是否是守护线程。

守护线程和用户线程的区别在于:守护线程依赖于创建它的线程,而用户线程则不依赖。

举个简单的例子:

如果在main线程中创建了一个守护线程,当main方法运行完毕之后,守护线程也会随着消亡。

而用户线程则不会,用户线程会一直运行直到其运行完毕。在JVM中,像垃圾收集器线程就是守护线程。

(10)Thread类有一个比较常用的静态方法currentThread()用来获取当前线程。

(11)holdsLock 判断线程是否有锁  Returns true if and only if the current thread holds the monitor lock on the specified object.


参考:

Java并发编程:Thread类的使用

http://www.cnblogs.com/dolphin0520/p/3920357.html

04 Thread的方法(源代码) 和 线程的状态的更多相关文章

  1. 注意!你的Thread.Abort方法真的让线程停止了吗?

    大家都知道在C#里面,我们可以使用 Thread.Start方法来启动一个线程,当我们想停止执行的线程时可以使用Thread.Abort方法来强制停止正在执行的线程,但是请注意,你确定调用了Threa ...

  2. C# Thread.Abort方法真的让线程停止了吗?

    大家都知道在C#里面,我们可以使用 Thread.Start方法来启动一个线程,当我们想停止执行的线程时可以使用Thread.Abort方法来强制停止正在执行的线程,但是请注意,你确定调用了Threa ...

  3. EF Core使用SQL调用返回其他类型的查询 ASP.NET Core 2.0 使用NLog实现日志记录 CSS 3D transforms cSharp:use Activator.CreateInstance with an Interface? SqlHelper DBHelper C# Thread.Abort方法真的让线程停止了吗? 注意!你的Thread.Abort方法真

    EF Core使用SQL调用返回其他类型的查询   假设你想要 SQL 本身编写,而不使用 LINQ. 需要运行 SQL 查询中返回实体对象之外的内容. 在 EF Core 中,执行该操作的另一种方法 ...

  4. java基础知识回顾之java Thread类学习(十)--线程的状态以及转化使用的方法介绍

       线程的概述:         线程是程序的多个执行路径,执行调度的单位,依托于进程存在.线程不仅可以共享进程的内存,而且还拥有一个属于自己的内存空间,这段内存空间叫做线程栈,是建立线程的时候由系 ...

  5. 注意Thread.interrupt()方法的真正作用并不是用来中断线程

      程序是很简易的.然而,在编程人员面前,多线程呈现出了一组新的难题,如果没有被恰当的解决,将导致意外的行为以及细微的.难以发现的错误.      在本篇文章中,我们针对这些难题之一:如何中断一个正在 ...

  6. Thread之十:停止线程方法汇总

    在上篇文章<多线程的使用——Thread类和Runnable接口>中提到中断线程的问题.在JAVA中,曾经使用stop方法来停止线程,然而,该方法具有固有的不安全性,因而已经被抛弃(Dep ...

  7. Java线程 - sleep()和wait()方法的区别, 线程阻塞BLOCKED和等待WAITING的区别

    一. sleep()和wait()方法的区别 sleep()方法 sleep()方法是Thread类的方法,通过其定义可知是个native方法,在指定的时间内阻塞线程的执行.而且从其注释中可知,并不会 ...

  8. Java 源码刨析 - 线程的状态有哪些?它是如何工作的?

    线程(Thread)是并发编程的基础,也是程序执行的最小单元,它依托进程而存在. 一个进程中可以包含多个线程,多线程可以共享一块内存空间和一组系统资源,因此线程之间的切换更加节省资源.更加轻量化,也因 ...

  9. Java如何监视线程的状态?

    在Java编程中,如何监视线程的状态? 以下示例演示如何通过扩展Thread类并使用currentThread.getName()方法来监视线程的状态. package com.yiibai; cla ...

随机推荐

  1. akka 练手 原来第一次是原封不动的返回传出去的参数

    今天,有介绍akka的文章,就下了个源码的demo练手! 在TimeServer 这个实例中主要就2个文件 server端 static void Main(string[] args) { usin ...

  2. Javascript设计模式理论与实战:组合模式

    我们平时开发过程中,一定会遇到这种情况:同时处理简单对象和由简单对象组成的复杂对象,这些简单对象和复杂对象会组合成树形结构,在客户端对其处理的时候要保持一致性.比如电商网站中的产品订单,每一张产品订单 ...

  3. Elasticsearch中的索引管理和搜索常用命令总结

    添加一个index,指定分片是3,副本是1 curl -XPUT "http://10.10.110.125:9200/test_ods" -d' { "settings ...

  4. 接口和抽象类的使用场景以及多类继承存在的问题(c#)

    我们首先来看下抽象class能发挥优势的使用场景. 假设有一个Cars基类,具体型号的Car继承该基类,并实现自己独有的属性或方法. public class Cars { public string ...

  5. WindowsPhone模拟简易Toast弹出框

    Coding4Fun这个开源控件中有ToastPrompt这个弹出框组件,但是由于Coding4Fun太庞大,如果只用到ToastPrompt这个控件的话,整个引用不太值当的.于是自己写了一个差不多的 ...

  6. C博客的第1次作业--分支,顺序结构

    1.本章学习总结 1.1 思维导图 1.2本章学习体会,代码量学习体会 1.2.1学习体会 初步了解什么是C语言,明白了这门语言的基本运行功能.了解了关于c语言结构上,语法上的基本知识.下一步要进一步 ...

  7. django系列1--介绍与简单原理, wsgiref模块

    一.web应用框架 Web应用框架(Web application framework)是一种计算机软件框架,用来支持动态网站.网络应用程序及网络服务的开发.这种框架有助于减轻网页开发时共通性活动的工 ...

  8. soundPool的使用

    SoundPool soundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 100); HashMap<Integer, Integer& ...

  9. linux进程管理(一)

    进程介绍 程序和进程 程序是为了完成某种任务而设计的软件,比如OpenOffice是程序.什么是进程呢?进程就是运行中的程序. 一个运行着的程序,可能有多个进程. 比如自学it网所用的WWW服务器是a ...

  10. java的string和==和equals和hashcode简单理解

    String s1= "abc"; s1是引用变量,在栈里面,如果java的String常量池中没有abc,则开拓一块区域存abc,s1指向常量池中的abc: String s2= ...