您的位置:首页 > 编程语言 > Java开发

java中线程阻塞之sleep、suspend、join、wait、resume、notify方法解析(一)

2015-03-27 13:51 1166 查看
java线程的5状态包括create、runnable、running、blocked、dead。

create是指用new线程被创建,但是还没有准备好各种资源。

runnable是指使用start启动线程,这时候系统会为线程分配除cpu以外的所有需要的资源。

running是指cpu只会调度处于runnable状态的线程使其占用cpu时间片真正开始运行。

blocked是指由于某种原因导致running中的线程暂停执行,被放到阻塞队列中,cpu不会再给他们分配时间片,直到导致阻塞的原因被解除而变为runnable状态。

dead指线程结束,包括正常结束(如执行完run方法)和非正常结束(如抛出异常等)。

那么造成blocked的原因有哪些呢?

(1) 调用 sleep(毫秒数),使线程进入“睡眠”状态。在规定的时间内,这个线程是不会运行的。

(2) 用 suspend()暂停了线程的执行。除非线程收到 resume() 消息,否则不会返回“可运行”状态。

(3) 用 wait()暂停了线程的执行。除非线程收到 nofify() 或者 notifyAll()消息,否则不会变成“可运行”(是的,看起来同原因 2 非常相象,但有一个明显区别是我们马上要揭示的)

(4) 线程正在等候一些 IO(输入输出)操作完成。

(5) 线程试图调用另一个对象的“同步”方法,但那个对象处于锁定状态,暂时无法使用。

先写两个基类:

class Blockable extends Thread {
private Peeker peeker;
protected int i;
public Blockable(){
peeker = new Peeker(this);
}

public synchronized int read(){ return i;}

public synchronized void update(){
System.out.println(this.getClass().getName()+"state :i = " + i);
}

public void stopPeeker(){
peeker.terminate();
}
}

class Peeker extends Thread {
private Blockable b;
private int session;
private boolean stop = false;

public Peeker(Blockable b){
this.b = b;
start();
}

public void run(){
while (!stop) {
System.out.println(b.getClass().getName()
+ " Peeker " + (++session)
+ "; value = " + b.read());
try {
sleep(1000);
} catch (InterruptedException e){}
}
}

public void terminate() {stop = true;}

}


Blockable 类打算成为本例所有类的一个基础类。一个 Blockable 对象包含了一个i信息。用于显示这些信息的方法叫作 update() 。我们发现它用

getClass.getName() 来产生类名,而不是仅仅把它打印出来;这是由于 update()不知道自己为其调用的那个类的准确名字,因为那个类是从 Blockable 衍生出来的。

在 Blockable 中,变动指示符是一个 int i;衍生类的 run()方法会为其增值。

针对每个 Bloackable 对象,都会启动 Peeker 类的一个线程。Peeker 的任务是调用 read()方法,检查与自己

关联的 Blockable 对象,看看 i 是否发生了变化,最后打印检查结果。注意 read()和 update() 都是同步的,要求对象的锁定能自由解除,这一点非常重要。

(1)sleep方法的调用阻塞自己时,也会引起其他线程阻塞是因为sleep不会释放对象锁。下是测试代码:

class Sleeper1 extends Blockable {

public Sleeper1() {
super();
}

public synchronized void run() {
while(true) {
i++;
update();
try {
sleep(1000);
} catch (InterruptedException e){}
}
}
}

class Sleeper2 extends Blockable {
public Sleeper2() {
super();
}

public void run() {
while(true) {
change();
try {
sleep(1000);
} catch (InterruptedException e){}
}
}

private synchronized void change(){
i++;
update();
}
}
public class SleepBlock {

public static void main(String[] args) {
new Sleeper1().start();
new Sleeper2().start();
}

}
我们会发现Sleeper1中的run方法是同步的,由于run方法里面是死循环,当Sleeper1线程启动后,Sleeper1内的Peeker线程根本无法运行。因为Sleeper1的sleep方法并不会释放对象锁。

在 Sleeper1 中,整个 run()方法都是同步的。我们可看到与这个对象关联在一起的 Peeker 可以正常运行,直到我们启动线程为止,随后 Peeker 便会完全停止。这正是“堵塞”的一种形式:因为 Sleeper1.run()是同步的,而且一旦线程启动,它就肯定在 run()内部,方法永远不会放弃对象锁定,造成 Peeker 线程的堵塞。

Sleeper2 通过设置不同步的运行,提供了一种解决方案。只有 change() 方法才是同步的,所以尽管 run()位于 sleep()内部,Peeker 仍然能访问自己需要的同步方法——read()。在这里,我们可看到在启动了Sleeper2 线程以后,Peeker 会持续运行下去。

(2)suspend方法调用阻塞自己时,引起其他线程阻塞也是因为suspend方法不会释放对象锁,这是不安全的。此方法已经废弃。因为使用suspend会发生一种很愚蠢的现象,就是自己把自己挂起,也就是进入阻塞状态。但是还抢着对象锁(前提是有同步方法访问同样的资源),这样其他线程来访问同步方法也只能傻傻等待。就好像你自己拿着钥匙在那等别人来开门,别人来开你又不给钥匙。自己阻塞后还不让别人获得锁从而执行,让别人也跟着在那儿等。

(3)wait方法阻塞自己时会释放对象锁,因此不会引起其他线程因得不到锁而阻塞,这一点和sleep、suspend是根本区别,因此他不会阻碍其他线程。

若必须等候其他某些条件(从线程外部加以控制)发生变化,同时又不想在线程内一直傻乎乎地等下去,一般就需要用到 wait()。wait()允许我们将线程置入“睡眠”状态,同时又“积极”地等待条件发生改变。而且只有在一个 notify() 或 notifyAll()发生变化的时候,线程才会被唤醒,并检查条件是否有变。因此,我们认为它提供了在线程间进行同步的一种手段。

我们也可以看到 wait()的两种形式。第一种形式采用一个以毫秒为单位的参数,它具有与 sleep()中相同的含义:暂停这一段规定时间。区别在于在 wait()中,对象锁已被解除,而且能够自由地退出 wait(),因为一个 notify() 可强行使时间流逝。第二种形式不采用任何参数,这意味着 wait()会持续执行,直到 notify() 介入为止。而且在一段时间以后,不会自行中止。

(4)IO引起的阻塞。这一部分主要是IO那一块的。由于访问IO可能会等待,因此会引起阻塞。

(5)在上面已经可以看出来了,不同线程在访问相同对象的同步方法时,会引起阻塞。需要等待一方先完成才能进行。

另外还有join()和yield()方法,

其中join的使用方式是threadname.join(),他的作用是让当前线程(注意当前线程不是threadname,而是执行这个语句的线程)阻塞,等待threadname线程执行完之后再执行,这也是我们所说的线程合并,因为它相当于把本来两条单独的执行路线合并到一起了。



但是yeild()方法根本都不是阻塞,他是让线程主动放弃cpu,等待下次调度,并没有被放入阻塞队列。

最后,如果一个程序线程很多,某些线程阻塞之后要想让其尽快解除阻塞去运行,就需要尽快让阻塞解除的条件发生。这时,需要弄清楚阻塞条件,如果有其他线程能加快该阻塞线程的阻塞解除速度,那么可以调整其他未阻塞线程的优先级,让未阻塞线程尽快多的执行从而加速阻塞线程解除阻塞,这里也就是动态调整线程优先级的方法来提高整个系统的运行效率。如果是IO阻塞,例如网络阻塞,那么这个时候可以从网络方面入手,如果是文件阻塞可以从磁盘IO入手。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐