一:JAVA中的线程
在java中线程的应用类主要在下面两个包中:
- java.lang
- java.util. concurrent
下图体现的是Java中最基础的线程类的关系拓扑图:
来看看java.lang.Runnable接口的源码:
package java.lang;
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
源码说明:
(1) Runnable中只有一个run()方法,且其类型是abstract()
(2) run()的解释:使用实现接口 Runnable 的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用对象的 run 方法。 方法 run 的常规协定是,它可能执行任何所需的动作。
Java.lang.Thread的源码:
package thread;
package java.lang;
...
/**
* 线程是程序中的执行线程,Java 虚拟机允许应用程序并发地运行多个执行线程。
* 每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。每一个线
* 程都可以或不可以标记为一个守护线程。当某个线程中运行的代码创建一个新
* Thread对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅
* 当创建线程是守护线程时,新线程才是守护线程。
* 当JAVA虚拟机启动时,通常都会有单个非守护线程(它通常会调用某个指定类的
* main方法)。Java 虚拟机会继续执行线程,直到下列任一情况出现时为止:
* 1:调用了Runtime类的exit()方法,并且安全管理器允许退出操作发生。
* 2:所有的非守护线程都停止运行,无论是通过从对 run 方法的调用中返回,还
是通过抛出一个传播到 run 方法之外的异常。
*/
public class Thread implements Runnable {
/* 确保registerNatives是client(端)做的第一件事。 */
private static native void registerNatives();
static {
registerNatives();
}
private char name[];
private int priority;
private Thread threadQ;
private long eetop;
/* 线程是否单步 */
private boolean single_step;
/* 线程是否是守护线程。 */
private boolean daemon = false;
/* JVM state */
private boolean stillborn = false;
/* 什么将被执行 */
private Runnable target;
/* 线程组 */
private ThreadGroup group;
/* 这个线程上下文类加载器 */
private ClassLoader contextClassLoader;
/* The inherited AccessControlContext of this thread */
private AccessControlContext inheritedAccessControlContext;
/* 用于自动编号的匿名线程 */
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
/**线程的初始状态:not yet started/
private volatile int threadStatus = 0;
/**一个线程可以拥有的最低优先级为:1**/
public final static int MIN_PRIORITY = 1;
/**分配给一个线程的缺省优先级为: 5*/
public final static int NORM_PRIORITY = 5;
/**一个线程可以拥有的最高优先级为:10**/
public final static int MAX_PRIORITY = 10;
/**暂停当前正在执行的线程对象,并执行其他线程。**/
public static native void yield();
/**在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。*/
public static native void sleep(long millis) throws InterruptedException;
/**
* 在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
* 参数:millis 以毫秒为单位的休眠时间。
* nanos 要休眠的另外 0-999999 纳秒。
*/
public static void sleep(long millis, int nanos)throws InterruptedException { ... }
/**初始化线程**/
private void init(ThreadGroup g, Runnable target, String name,long stackSize) {}
/** 分配新的 Thread 对象. **/
public Thread() { init(null, null, "Thread-" + nextThreadNum(), 0);}
/**
* 分配新的 Thread 对象.
* 参数:target - 任务
*/
public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0);}
/**
* 分配新的 Thread 对象.
* 参数:name - 新线程的名称
* target - 任务
*/
public Thread(Runnable target, String name) { init(null, target, name, 0);}
/**
* 分配新的 Thread 对象.
* 参数:name - 新线程的名称
*/
public Thread(String name) { init(null, null, name, 0); }
/**
* 分配新的 Thread 对象.
* 参数:group - 线程组
* target - 任务
* 异常:SecurityException - 如果当前线程无法在指定的线程组中创建线程
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);
}
/**
* 分配新的 Thread 对象.
* 参数:name - 新线程的名称
* group - 线程组
* 异常:SecurityException - 如果当前线程无法在指定的线程组中创建线程
*/
public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);
}
/**
* 分配新的 Thread 对象.
* 参数:name - 新线程的名称
* target - 任务
* group
* 异常:SecurityException 如果当前线程不能在指定的线程组中创建线程或无法重写上下文类加载器的方法。
*/
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
}
/**
* 分配新的Thread对象,以便将target作为其运行对象,将指定的name作为其名称,属于由组提到的线程组,并具有指定的堆栈大小。
* 参数:name - 新线程的名称 target - 任务 group - 线程组 stackSize - 栈大小
* 异常:SecurityException 如果当前线程不能在指定的线程组中创建线程
*/
public Thread(ThreadGroup group, Runnable target, String name,long stackSize) {
init(group, target, name, stackSize);
}
/**
* 使该线程开始执行; Java虚拟机调用该线程的run方法。
* 其结果是两个线程同时运行,当前线程(该线程从调用start()方法返回)和另一个线程(该线程执行它的run()方法)。
* 多次启动一个线程是无效的。 特别是当一个线程完成后,再被启动。
* @exception IllegalThreadStateException 如果线程已经启动
*/
public synchronized void start() {...}
private native void start0();
/**
* 如果该线程使用了一个单独的Runnable进行对象构造,运行对象,则Runnable对象的run方法被调用。
* 否则,此方法不执行任何操作并返回。
*/
@Override
public void run() {
if (target != null) {
target.run();
}
}
/**该方法被系统调用,主要是退出前进行清理工作**/
private void exit() {
if (group != null) {
group.threadTerminated(this);
group = null;
}
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
/* Speed the release of some of these resources */
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
}
源码说明:
(1) 其实现了Runnable接口,而Runnable接口有一个run()方法,所以Thread也实现了该方法。
(2) 从其构造函数中的如下代码:
init(null, null, "Thread-" + nextThreadNum(), 0);
可以看出,线程名称创建的规则是:”Thread-”+创建的线程的个数(第几个线程)
二:JAVA中线程的状态
1) New(新建) 新建的、至今尚未启动的线程处于这种状态。
2) Runnable(可运行状态): 包括就绪、运行中两个状态
(1)Ready(就绪): 程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权 。
(2)Running(运行中): 可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,正在执行程序代码。
3) Wait/Blocked(暂停运行/阻塞):
Wait/Blocked状态是指线程因为某种原因放弃了cpu 使用权,即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。Wait/Blocked的情况分三种:
(1). Timed Waiting:调用如下方法,线程处于暂停运行状态,直到等待时间已过,线程重新转入可运行(runnable)状态。
sleep(long timeout)
wait(long timeout)
wait(long timeout, int nanos)
join(long millis)
join(long millis, int nanos)
LockSupport.parkNanos(long nanos)
LockSupport.parkUntil(long deadline)
(2). Waiting: 某一等待线程的线程状态。某一线程因为调用下列方法之一而处于等待状态,直到针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
不带超时值的 Object.wait()
不带超时值的 Thread.join()
LockSupport.park()
(3). Blocked:受阻塞并且正在等待监视器锁的某一线程的线程状态。处于受阻塞状态的某一线程正在等待监视器锁,以便进入一个同步的块/方法,或者在调用 Object.wait 之后再次进入同步的块/方法。
4) Terminated(终止):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。
线程的生命周期图
三:线程的分类
Java线程可以分两类:
1.守护线程(daemon threads)
守护线程通常为普通线程提供服务,它们通常有一个无限循环,等待服务请求或执行线程的任务,在没有其他的非守护线程运行时,守护线程将停止工作。即使你不创建任何线程,Java应用程序在默认情况下创建多个线程。他们大多是守护线程,主要用于处理任务,如垃圾收集或JMX。
守护线程的特点:
- 优先级非常低
- 只有当同一个程序的任何其他线程正在运行时执行。
- 当线程只剩下守护线程的时候,JVM就会退出.但是如果还有其他的任意一个用户线程还在,JVM就不会退出.
2.非守护线程 (non-daemon threads)或普通线程或用户线程(user threads)
用户线程和守护线程两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果用户线程已经全部退出运行了,只剩下守护线程存在了,虚拟机也就退出了。 因为没有了被守护者,守护线程也就没有工作可做了,也就没有继续运行程序的必要了
在JAVA中通过调方法Thread.setDaemon(true)将线程转为守护线程。但需要注意的有:
1)但必须在调Thread.start()方法之前,因为一旦线程正在运行,你不能修改它的守护进程的状态。
2)在Daemon线程中产生的新线程也是Daemon的
3)守护线程应该永远不去访问固有资源,如文件、数据库,因为它会在任何时候甚至在一个操作的中间发生中断。
举例:
package thread;
public class DaemonTest {
public static void main(String[] args) {
new WorkerThread().start();
try {
Thread.sleep(7500);
} catch (InterruptedException e) {}
System.out.println("Main Thread ending") ;
}
}
class WorkerThread extends Thread {
public WorkerThread() {
System.out.println("线程是否为守护线程: "+this.isDaemon());
// When false, (i.e. when it's a user thread),
// the Worker thread continues to run.
// When true, (i.e. when it's a daemon thread),
// the Worker thread terminates when the main
// thread terminates.
setDaemon(true) ;
System.out.println("线程是否为守护线程: "+this.isDaemon());
}
public void run() {
int count=0 ;
while (true) {
System.out.println("Hello from Worker "+count++) ;
try {
sleep(5000);
} catch (InterruptedException e) {}
}
}
}
参考资料:
http://blog.csdn.net/yyc1023/article/details/17428633
http://uule.iteye.com/blog/1100799
http://my.oschina.net/mingdongcheng/blog/139263
http://blog.csdn.net/yyc1023/article/details/17428633
http://www1.huachu.com.cn/read/readbookinfo.asp?sectionid=1000005042
http://lavasoft.blog.51cto.com/62575/99153
http://www.cnblogs.com/jinglingJuly/archive/2013/06/02/3113397.html
http://52android.blog.51cto.com/2554429/468031/
http://www.uml-diagrams.org/examples/java-6-thread-state-machine-diagram-example.html
http://www.cjsdn.net/doc/jdk50/java/lang/Thread.State.html
http://architects.dzone.com/articles/how-analyze-java-thread-dumps
http://stackoverflow.com/questions/2213340/what-is-daemon-thread-in-java