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()方法,这个线程就会释放这个对象所持有的同步资源(不会释放其他对象的同步锁)。jdk api doc:The current thread must own this object‘s monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object‘s monitor to wake up either through a call to the notify method or the notifyAll method
- 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不会运行。
- * */
- }