线程相关

实现线程的法子 有两种:
1. 继承java.lang.Thread,并重写它的run()法子 ,将线程的履行主体放入其中。
2. 实现java.lang.Runnable接口,实现它的run()法子 ,并将线程的履行主体放入其中。

public class ThreadTest extends Thread {
public void run() {
// 在这里编写线程履行
的主体
// do something
}
}

 

public class RunnableTest implements Runnable {
public void run() {
// 在这里编写线程履行
的主体
// do something
}
}

这两种实现法子 的差别并不大。继承Thread类的法子 实现起来较为简略,但是继承它的类
就不能再继承别的类了,因此也就不能继承别的类的有用的法子 了。而应用是想Runnable
接口的法子 就不存在这个问题了,而且这种实现法子 将线程主体和线程对象本身分手开来,
逻辑上也较为清楚,所以推选大家更多地采纳这种法子 。

 

如何启动线程
我们通过以上两种法子 实现了一个线程之后,线程的实例并没有被创立,因此它们也并没有
被运行。我们要启动一个线程,必须 调用法子 来启动它,这个法子 就是Thread类的start()方
法,而不是run()法子 (既不是我们继承Thread类重写的run()法子 ,也不是实现Runnable接
口的run()法子 )。run()法子 中包孕的是线程的主体,也就是这个线程被启动后将要运行的
代码,它跟线程的启动没有任何关系。上面两种实现线程的法子 在启动时会有所不同。

继承Thread类的启动法子 :

 

public class ThreadStartTest {
public static void main(String[] args) {
// 创立
一个线程实例
ThreadTest tt = new ThreadTest();
// 启动线程
tt.start();
}
}

 

实现Runnable接口的启动法子 :

public class RunnableStartTest {
public static void main(String[] args) {
// 创立
一个线程实例
Thread t = new Thread(new RunnableTest());
// 启动线程
t.start();
}
}

 

实际上这两种启动线程的法子 原理是一样的。首先都是调用本地法子 启动一个线程,其次是
在这个线程里履行目标 对象的run()法子 。那么这个目标 对象是什么呢?为了弄明白这个问
题,我们来看看Thread类的run()法子 的实现:

public void run() {
if (target != null) {
target.run();
}
}

 

当我们采纳实现Runnable接口的法子 来实现线程的情况 下,在调用new Thread(Runnable
target)结构器时,将实现Runnable接口的类的实例设置成了线程要履行的主体所属的目标 对
象target,当线程启动时,这个实例的 run()法子 就被履行了。当我们采纳继承Thread的方
式实现线程时,线程的这个run()法子 被重写了,所以当线程启动时,履行的是这个对象自
身的 run()法子 。总结起来就一句话,线程类有一个Runnable类型的target属性,它是线程
启动后要履行的run()法子 所属的主体,如果我们采纳的是继承Thread类的法子 ,那么这个
target就是线程对象自身,如果我们采纳的是实现Runnable接口的法子 ,那么这个target就
是实现了Runnable接口的类的实例。

 

线程的状态

在Java 1.4及以下的版本中,每个线程都具有新建、可运行、阻塞、逝世亡四种状态 ,但是在
Java 5.0及以上版本中,线程的状态 被扩充为新建、可运行、阻塞、等候、定时等候、逝世亡
六种。线程的状态 完整包孕了一个线程从新建到运行,最后到收场的全部生命 周期。线程状
态的具体信息如下:
1. NEW(新建状态 、初始化状态 ):线程对象已经被创立,但是还没有被启动时的状态 。
这段光阴就是在我们调用new命令之后,调用start()法子 之前。
2. RUNNABLE(可运行状态 、就绪状态 ):在我们调用了线程的start()法子 之后线程所
处的状态 。处于RUNNABLE状态 的线程在JAVA虚拟机(JVM)上是运行着的,但是它可
能还正在等候操作系统 分配给它相应的运行资源以得以运行。
3. BLOCKED(阻塞状态 、被中断 运行):线程正在等候其它的线程释放同步锁,以进
入一个同步块或者同步法子 持续运行;或者它已经进入了某个同步块或同步法子 ,在运行的
历程中它调用了某个对象继承自java.lang.Object的wait()法子 ,正在等候重新返回这个同步
块或同步法子 。
4. WAITING(等候状态 ):当前线程调用了java.lang.Object.wait()、
java.lang.Thread.join()或者java.util.concurrent.locks.LockSupport.park()三个中的任意一个法子 ,
正在等候另外一个线程履行某个操作。比如一个线程调用了某个对象的wait()法子 ,正在等
待其它线程调用这个对象的notify() 或者notifyAll()(这两个法子 同样是继承自Object类)方
法来唤醒它;或者一个线程调用了另一个线程的join()(这个法子 属于 Thread类)法子 ,正
在等候这个法子 运行收场。
5. TIMED_WAITING(定时等候状态 ):当前线程调用了 java.lang.Object.wait(long
timeout)、java.lang.Thread.join(long
millis)、java.util.concurrent.locks.LockSupport.packNanos(long
nanos)、java.util.concurrent.locks.LockSupport.packUntil(long deadline)四个法子 中的任意一个,
进入等候状态 ,但是与WAITING状态 不同的是,它有一个最大等候光阴,即使等候的条件
仍然没有满足,只要到了这个光阴它就会主动醒来。
6. TERMINATED(逝世亡状态 、终止状态 ):线程完成履行后的状态 。线程履行完run()方
法中的整个代码,从该法子 中退出,进入TERMINATED状态 。还有一种情况 是run()在运行
历程中抛出了一个异常,而这个异常没有被程序捕获,导致这个线程异常终止进入
TERMINATED状态 。

在Java5.0及以上版本中,线程的整个六种状态 都以枚举类型的情势定义在java.lang.Thread
类中了,代码如下:

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

sleep()和wait()的差别
sleep()法子 和wait()法子 都成产生 让当前运行的线程收场运行的效果 ,这是它们的共同点。
下面我们来详细说说它们的不同之处。

 

public static native void sleep(long millis) throws InterruptedException;
public static void sleep(long millis, int nanos) throws InterruptedException {
//other code
}

其中的参数millis代表毫秒数(千分之一秒),nanos代表纳秒数(十亿分之一秒)。这两
个法子 都可以让调用它的线程沉睡(收场运行)指定的光阴,到了这个光阴,线程就会主动
醒来,变为可运行状态 (RUNNABLE),但这并不表现它马上就会被运行,因为线程调度
机制恢复线程的运行也需要 光阴。调用sleep()法子 并不会让线程释放它所持有的同步锁;而
且在这期间它也不会阻碍其它线程的运行。上面的连个法子 都声明抛出一个
InterruptedException类型的异常,这是因为线程在sleep()期间,有可能被持有它的引用的其
它线程调用它的 interrupt()法子 而中断 。中断 一个线程会导致一个InterruptedException异常
的产生 ,如果你的程序不捕获这个异常,线程就会异常终止,进入TERMINATED状态 ,如
果你的程序捕获了这个异常,那么程序就会持续履行 catch语句块(可能还有finally语句块)
以及以后的代码。

为了更好地了解interrupt()效果 ,我们来看一下下面这个例子:

public class InterruptTest {
public static void main(String[] args) {
Thread t = new Thread() {
public void run() {
try {
System.out.println("我被履行
了-在sleep()法子


前");
// 收场运行10分钟
Thread.sleep(1000 * 60 * 60 * 10);
System.out.println("我被履行
了-在sleep()法子


后");
} catch (InterruptedException e) {
System.out.println("我被履行
了-在catch语句块中");
}
System.out.println("我被履行
了-在try{}语句块后");
}
};
// 启动线程
t.start();
// 在sleep()收场
前中断

它
t.interrupt();
}
}

 

运行效果:
1. 我被履行了-在sleep()法子 前
2. 我被履行了-在catch语句块中
3. 我被履行了-在try{}语句块后

 

wait()法子 也是本地法子 ,属于Object类,有三个定义:

 

 

 

public final void wait() throws InterruptedException {
//do something
}
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException {
//do something
}

wari()和wait(long timeout,int nanos)法子 都是基于wait(long timeout)法子 实现的。同样地,
timeout代表毫秒数,nanos代表纳秒数。当调用了某个对象的wait()法子 时,当前运行的线
程就会转入等候状态 (WAITING),等候别的线程再次调用这个对象的notify()或者
notifyAll()法子 (这两个法子 也是本地法子 )唤醒它,或者到了指定的最大等候光阴,线程
主动醒来。如果线程拥有某个或某些对象的同步锁,那么在调用了wait()后,这个线程就会
释放它持有的所有同步资源,而不限于这个被调用了wait()法子 的对象。wait()法子 同样会被
Thread类的interrupt()法子 中断 ,并产生 一个 InterruptedException异常,效果 同sleep()法子
被中断 一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值