您的位置:首页 > 大数据 > 人工智能

线程:sleep()、wait()、yield()和join()方法

2015-11-02 19:42 447 查看
欢迎大家访问我的博客[b]http://blog.csdn.net/mikejaps专注于android
ios app 开发
[/b]

1.sleep()和wait()

这两个方法都可以让调用它的线程沉睡(sleep)/停止运行(wait)指定的时间,到了这个时间,线程就会自动醒来,变为可运行状态(RUNNABLE)。

public static native void sleep(long millis) throws InterruptedException;

public static void sleep(long millis, int nanos) throws InterruptedException

public final void wait() throws InterruptedException

public final native void wait(long timeout) throws InterruptedException;

public final void wait(long timeout, int nanos) throws InterruptedException

Parameters:

millis - the length of time to sleep in milliseconds.毫秒数

nanos - 0-999999 additional nanoseconds to sleep.纳秒数

调用sleep()方法并不会让线程释放它所持有的同步锁;而且在这期间它也不会阻碍其它线程的运行。

当调用了某个对象的wait()方法时,当前运行的线程就会转入WAITING状态,等待别的线程再次调用这个对象的notify()或者notifyAll()方法唤醒它,或者到了指定的最大等待时间,线程自动醒来。如果线程调用了某个对象的wait()方法,这个线程就会释放这个对象所持有的同步资源(不会释放其他对象的同步锁)。

package edu.hust.test;

public class ThreadSleep implements Runnable {

/*

* 让线程睡眠的理由很多,比如(1)认为该线程运行得太快,需要减缓一下,以便和其他线程协调;(2)查询当时的股票价格,每睡5分钟查询一次,可以节省带宽,而且即时性要求也不那么高。

* 注意:时间的精确性。线程醒来之后不会马上运行,而要等待cpu给其分配时间片。因此sleep()中指定的时间并不是线程不运行的精确时间!所以不能依赖sleep()方法提供十分精确的定时。

* 我们可以看到很多应用程序用sleep()作为定时器,实际是不精确的。

*

*

* Thread.sleep(5 * 1000)和Thread.currentThread().sleep(5 * 1000)没区别:都表示让当前线程sleep 5秒.

* 一个是通过类获取静态方法,一个是通过实例对象获得静态方法(sleep()为静态方法).

*

* 注意:sleep并不是Thread的一个STATE

*/

public void execute() {

synchronized(this) {

try {

System.out.println(Thread.currentThread().getName() + ", sleep()前");

Thread.sleep(1000);

System.out.println(Thread.currentThread().getName() + ", sleep()后");

} catch (InterruptedException e) {

System.out.println(Thread.currentThread().getName() + ", 谁把我吵醒了.....");

}

//此处如果使用System.err, 会有很意外的结果。System.out和System.err的区别请见blog

System.out.println(Thread.currentThread().getName() + ", run()结束..进入TERMINATED状态");

}

}

public void run() {

execute();

}

public static void main(String[] args) throws InterruptedException {

ThreadSleep threadSleep = new ThreadSleep();

Thread[] threads = new Thread[5];

System.out.println(Thread.currentThread().getName() + "线程的状态为:" + Thread.currentThread().getState());

for (Thread thread : threads) {

thread = new Thread(threadSleep);

thread.start();

if ("Thread-1".equals(thread.getName()) || "Thread-3".equals(thread.getName()))

thread.interrupt();

}

}

/*

* 某次运行结果:

* main线程的状态为:RUNNABLE

* Thread-1, sleep()前

* Thread-1, 谁把我吵醒了.....

* Thread-1, run()结束..进入TERMINATED状态

*

* Thread-3, sleep()前

* Thread-3, 谁把我吵醒了.....

* Thread-3, run()结束..进入TERMINATED状态

*

* Thread-0, sleep()前

* Thread-0, sleep()后

* Thread-0, run()结束..进入TERMINATED状态

*

* Thread-2, sleep()前

* Thread-2, sleep()后

* Thread-2, run()结束..进入TERMINATED状态

*

* Thread-4, sleep()前

* Thread-4, sleep()后

* Thread-4, run()结束..进入TERMINATED状态

*

* 从运行结果可以得出很多结论, 其中之一是:调用sleep()方法并不会让线程释放它所持有的同步锁;而且在这期间它也不会阻碍其它线程的运行。

*

* */

}

package edu.hust.test;

class MyThread1 implements Runnable {

private Object obj;

public MyThread1(Object o) {

obj = o;

}

public void run() {

synchronized (obj) { //这里是给obj对象(也就是str="爱吃土豆")加锁, 如写成synchronized (this), 则表示是给myThread1加锁.

try {

System.out.println("MyThread1进入wait状态");

obj.wait();

System.out.println("MyThread1被notify");

} catch (InterruptedException e) {

System.err.println("谁把我吵醒了.....");

}

}

}

}

class MyThread2 implements Runnable {

private Object obj;

public MyThread2(Object o) {

obj = o;

}

public void run() {

synchronized (obj) { //这里是给obj对象(也就是str="爱吃土豆")加锁, 如写成synchronized (this), 则表示是给myThread2加锁.

System.out.println("MyThread2调用notify()方法");

obj.notify();

}

}

}

public class ThreadWait {

public static void main(String[] args) {

//错误的写法, 这里myThread1和myThread2操作的是两个不同的对象.

//Thread myThread1 = new Thread(new MyThread1(new String("爱吃土豆")));

//Thread myThread2 = new Thread(new MyThread2(new String("爱吃土豆")));

//正确的写法, 这里myThread1和myThread2操作的是同一个对象.

String str = "爱吃土豆";

Thread myThread1 = new Thread(new MyThread1(str));

Thread myThread2 = new Thread(new MyThread2(str));

myThread1.start();

myThread2.start();

}

/*

* 运行结果:

* MyThread1进入wait状态

* MyThread2调用notify()方法

* MyThread1被notify

*

* 这里使用了synchronized块来包装某个实例对象(String str = "爱吃土豆")的wait()和notify()方法, 这是由于调用这两个方法的时候线程必须获得同步锁.

* 如果synchronized包装的不是同一个实例对象的wait()和notify()方法, 则表示给wait()和notify()加的锁不是同一把锁,eg:将synchronized(lock)改为synchronized(this).

* 将会抛出java.lang.IllegalMonitorStateException, 告诉你current thread not owner.

*

* */

/*

* 摘录:

* 多线程常用的一些方法: wait(),wait(long),notify(),notifyAll()

* wait() 是使持有对象锁的线程释放锁;

* wait(long) 是使持有对象锁的线程释放锁时间为long(毫秒)后,再次获得锁,wait()和wait(0)等价;

* notify() 是唤醒一个正在等待该对象锁的线程,如果等待的线程不止一个,那么被唤醒的线程由jvm确定;

* notifyAll 是唤醒所有正在等待该对象锁的线程.

*

* 应该优先使用notifyAll()方法, 因为唤醒所有线程比唤醒一个线程更容易让jvm找到最适合被唤醒的线程.

* 对于上述方法,只有在当前线程中才能使用,否则报运行时错误java.lang.IllegalMonitorStateException: current thread not owner.

* 从实现角度来分析:

* 在线程调用wait()方法时,需要把它放到一个同步段里,否则将会出现"java.lang.IllegalMonitorStateException: current thread not owner"的异常。

*

* */

}

package edu.hust.test;

public class ThreadWait2 implements Runnable {

private Object monitor1 = new Object();

private Object monitor2 = new Object();

public void run() {

synchronized (monitor1) {

System.out.println("monitor1被锁住了");

synchronized (monitor2) {

System.out.println("monitor2被锁住了");

try {

System.out.println("monitor2进入wait()状态");

monitor2.wait();

} catch (InterruptedException e) {

System.out.println("谁把我吵醒了.....");

}

}

}

}

public void getMonitor() throws InterruptedException {

Thread.sleep(3 * 1000); //让main Thread延迟3秒执行, 使myThread获得足够时间进行线程初始化

synchronized (monitor2) {

System.out.println("我取得了monitor2");

}

synchronized (monitor1) {

System.out.println("我取得了monitor1");

}

}

public static void main(String[] args) {

ThreadWait2 threadWait2 = new ThreadWait2();

Thread myThread = new Thread(threadWait2);

myThread.start();

try {

threadWait2.getMonitor();

} catch (InterruptedException e) {

System.out.println("谁把我吵醒了.....");

}

}

/*

* 因为wait()方法没有被notify(), 所以程序不会自动结束. 但运行结果不会改变了:

* monitor1被锁住了

* monitor2被锁住了

* monitor2进入wait()状态

* 我取得了monitor2

*

* 分析:System.out.println("我取得了monitor1")这句话永远不会得到执行, 因为wait()被调用时只释放了monitor2的锁, 并没有释放monitor1的锁.

* */

}

2. yield()

让当前运行Thread放弃其所占用的cpu时间片,以便让其他Thread运行。用yield()方法的目的是让Thread能适当地轮转。但是,并不能保证达到此效果!因为,即使当前Thread放弃时间片,可是还有可能再次被JVM选中!也就是连任。

3. join()

package edu.hust.test;

public class ThreadJoin {

public void run() {

System.out.println("普通打印语句1");

System.out.println("普通打印语句2");

}

public static void main(String[] args) throws InterruptedException {

Thread myThread = new Thread() {

public void run() {

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

System.err.println("谁把我吵醒了.....");

}

System.out.println("线程:" + Thread.currentThread().getName() + " 启动了");

}

};

myThread.start();

myThread.join();

new ThreadSeq().run();

}

/*

* 没有t.join(), 运行结果为:

* 普通打印语句1

* 普通打印语句2

* 线程:Thread-0 启动了

*

* 加入t.join(), 运行结果为:

* 线程:Thread-0 启动了

* 普通打印语句1

* 普通打印语句2

*

* join():让当前Thread加入到myThread线程的尾部,意味着myThread线程运行结束之前,当前Thread不会运行。使调用join()的线程执行完毕后才能执行其它线程,在一定意义上,它可以实现同步的功能

* */

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: