`

thread 线程中的sleep()、wait()、yield()、join()用法介绍

阅读更多
从操作系统的角度讲,os会维护一个ready queue(就绪的线程队列)。并且在某一时刻cpu只为ready queue中位于队列头部的线程服务。
但是当前正在被服务的线程可能觉得cpu的服务质量不够好,于是提前退出,这就是yield。
或者当前正在被服务的线程需要睡一会,醒来后继续被服务,这就是sleep。
sleep方法不推荐使用,可用wait。
线程退出最好自己实现,在运行状态中一直检验一个状态,如果这个状态为真,就一直运行,如果外界更改了这个状态变量,那么线程就停止运行。


1.sleep()方法

在指定时间内让当前正在执行的线程暂停执行,但不会释放“锁标志”。不推荐使用。

sleep()使当前线程进入阻塞状态,在指定时间内不会执行。

2.wait()方法

在其他线程调用对象的notify或notifyAll方法前,导致当前线程等待。线程会释放掉它所占有的“锁标志”,从而使别的线程有机会抢占该锁。

当前线程必须拥有当前对象锁。如果当前线程不是此锁的拥有者,会抛出IllegalMonitorStateException异常。

唤醒当前对象锁的等待线程使用notify或notifyAll方法,也必须拥有相同的对象锁,否则也会抛出IllegalMonitorStateException异常。

waite() 和notify()必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生 IllegalMonitorStateException的异常。

3.yield方法

暂停当前正在执行的线程对象。

yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。
yield()也不会释放锁标志。

  实际上,yield()方法对应了如下操作;先检测当前是否有相同优先级的线程处于同可运行状态,如有,则把CPU的占有权交给次线程,否则继续运行原来的线程,所以yield()方法称为“退让”,它把运行机会让给了同等级的其他线程。

yield()只能使同优先级或更高优先级的线程有执行的机会。

4.join方法

等待该线程终止。

等待调用join方法的线程结束,再继续执行。如:t.join();//主要用于等待t线程运行结束,若无此句,main则会执行完毕,导致结果不可预测。


彻底明白多线程通信机制:

  线程间的通信
1.    线程的几种状态
线程有四种状态,任何一个线程肯定处于这四种状态中的一种:
1)    产生(New):线程对象已经产生,但尚未被启动,所以无法执行。如通过new产生了一个线程对象后没对它调用start()函数之前。
2)    可执行(Runnable):每个支持多线程的系统都有一个排程器,排程器会从线程池中选择一个线程并启动它。当一个线程处于可执行状态时,表示它可能正处于线程池中等待排排程器启动它;也可能它已正在执行。如执行了一个线程对象的start()方法后,线程就处于可执行状态,但显而易见的是此时线程不一定正在执行中。
3)    死亡(Dead):当一个线程正常结束,它便处于死亡状态。如一个线程的run()函数执行完毕后线程就进入死亡状态。
4)    停滞(Blocked):当一个线程处于停滞状态时,系统排程器就会忽略它,不对它进行排程。当处于停滞状态的线程重新回到可执行状态时,它有可能重新执行。如通过对一个线程调用wait()函数后,线程就进入停滞状态,只有当两次对该线程调用notify或notifyAll后它才能两次回到可执行状态。

2.    class Thread下的常用函数函数
2.1    suspend()、resume()
1)    通过suspend()函数,可使线程进入停滞状态。通过suspend()使线程进入停滞状态后,除非收到resume()消息,否则该线程不会变回可执行状态。
2)    当调用suspend()函数后,线程不会释放它的“锁标志”。

2.2     sleep()
1)    sleep ()函数有一个参数,通过参数可使线程在指定的时间内进入停滞状态,当指定的时间过后,线程则自动进入可执行状态。
2)    当调用sleep ()函数后,线程不会释放它的“锁标志”。


2.3    yield()
1)    通过yield ()函数,可使线程进入可执行状态,排程器从可执行状态的线程中重新进行排程。所以调用了yield()的函数也有可能马上被执行。
2)    当调用yield ()函数后,线程不会释放它的“锁标志”。
例:
    class TestThreadMethod extends Thread{
        public static int shareVar = 0;
        public TestThreadMethod(String name){
            super(name);
        }
        public synchronized void run(){
            for(int i=0; i<4; i++){
                System.out.print(Thread.currentThread().getName());
                System.out.println(" : " + i);
                Thread.yield();
            }
        }
    }
    public class TestThread{
        public static void main(String[] args){
            TestThreadMethod t1 = new TestThreadMethod("t1");
            TestThreadMethod t2 = new TestThreadMethod("t2");
            t1.start();
            t1.start(); //(1)
            //t2.start(); (2)
        }
}
运行结果为:
t1 : 0
t1 : 1
t1 : 2
t1 : 3
t1 : 0
t1 : 1
t1 : 2
t1 : 3
从结果可知调用yield()时并不会释放对象的“锁标志”。
                如果把代码(1)注释掉,并去掉代码(2)的注释,结果为:
t1 : 0
t1 : 1
t2 : 0
t1 : 2
t2 : 1
t1 : 3
t2 : 2
t2 : 3
从结果可知,虽然t1线程调用了yield(),但它马上又被执行了。



//java.lang.IllegalThreadStateException异常解释

You are storing the thread in a field. If the method is called in two threads, the readThread.start() can be called twice for the same thread. You need to ensure readCommand is not called multiple times and perhaps not start the readThread again if its already running. e.g. you can synchronized the method and check readThread before you start.

A thread will throw the exception when calling start if the thread's state (as retrieved by Thread.currentThread().getState() is anything other than NEW.

The source;

public synchronized void start() {
    /*
     * A zero status value corresponds to state "NEW".
     */
    if (threadStatus != 0)
        throw new IllegalThreadStateException();
    group.add(this);
    start0();
    if (stopBeforeStart) {
        stop0(throwableFromStop);
    }
}
This means, your thread is in one of the other states, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING or TERMINATED.

You could have a look at the state of the threads via a thread dump or JConsole to see what yours is doing. You can programmatically take a thread dump right before the call to start using something like tempus-fugit if that helps.

UPDATE: In response to your comments, if you interrupt a thread which in your case, I assume will set the running flag to false, the thread will still be RUNNABLE. To 'resume' work on the thread (again, I'm assuming that's what you want to do), you would change the running flag again. Calling start will fail because it's already started. You could also let the thread die on interruption and then just create a new instance of a Thread and "start" that one as an alternative.


2.4    sleep()和yield()的区别
1)    sleep()使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会执行;yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。
2)    sleep()可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会;yield()只能使同优先级的线程有执行的机会。

2.5    join()
使调用join()的线程执行完毕后才能执行其它线程,在一定意义上,它可以实现同步的功能。


3. class Object下常用的线程函数
wait()、notify()和notifyAll()这三个函数由java.lang.Object类提供,用于协调多个线程对共享数据的存取。
3.1 wait()、notify()和notifyAll()
1) wait()函数有两种形式:第一种形式接受一个毫秒值,用于在指定时间长度内暂停线程,使线程进入停滞状态。第二种形式为不带参数,代表waite()在notify()或notifyAll()之前会持续停滞。
2) 当对一个对象执行notify()时,会从线程等待池中移走该任意一个线程,并把它放到锁标志等待池中;当对一个对象执行notifyAll()时,会从线程等待池中移走所有该对象的所有线程,并把它们放到锁标志等待池中。
3) 当调用wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其它synchronized数据可被别的线程使用。

3.2 wait()、notify()和synchronized
waite()和notify()因为会对对象的“锁标志”进行操作,所以它们必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。

4.1 这两组函数的区别
1) wait()使当前线程进入停滞状态时,还会释放当前线程所占有的“锁标志”,从而使线程对象中的synchronized资源可被对象中别的线程使用;而suspend()和sleep()使当前线程进入停滞状态时不会释放当前线程所占有的“锁标志”。
2) 前一组函数必须在synchronized函数或synchronized block中调用,否则在运行时会产生错误;而后一组函数可以non-synchronized函数和non-synchronized block中调用。













分享到:
评论

相关推荐

    Java线程中wait,await,sleep,yield,join用法总结.pdf

    以上就是对Java线程中wait、await、sleep、yield、join用法的总结。这些方法在实际开发中,对于控制多线程运行的时序和协调非常关键。理解这些方法的正确使用方式是掌握Java并发编程的基础。同时,使用时需特别注意...

    线程中sleep、join、yield、wait的区别

    本文将详细解析线程中`sleep()`, `join()`, `yield()`, 和 `wait()` 四个方法的区别。 1. `sleep()` `sleep()` 方法是 `java.lang.Thread` 类的一个静态方法,它允许当前正在执行的线程在指定的毫秒数内暂停执行。...

    sleep()、wait()、yield()和join()方法特点及区别.docx

    本文将深入探讨Java中的四个关键方法:`sleep()`, `wait()`, `yield()`和`join()`,以及它们各自的特点和区别。 首先,我们来看`sleep()`和`wait()`的区别: 1. **来源不同**:`sleep()`是`Thread`类的方法,它...

    高薪程序员面试题精讲系列63之说说sleep()、yield()、join()、wait()的区别.pdf,这是一份不错的文件

    本资源主要讲解了Java中四个常用的线程控制方法:sleep()、yield()、join()和wait(),它们是Java多线程编程中的重要组成部分。下面是对每个方法的详细讲解: 1. sleep()方法: sleep()方法是Thread类...

    Thread 线程 java编程 亲手测试了的

    1. **join()**:让当前线程等待指定线程结束,调用`join()`方法的线程会暂停执行,直到目标线程完成其任务。 2. **sleep()**:使当前线程暂停指定毫秒数,然后继续执行。 3. **yield()**:让当前线程放弃CPU执行权...

    java多线程Demo

    创建一个实现了Runnable接口的类,然后在实现的`run()`方法中编写线程任务。接着,将Runnable对象传递给Thread类的构造函数,创建Thread对象并启动。这种方式更灵活,因为类可以实现多个接口,如下所示: ```java ...

    JAVA 线程中启动线程

    - **实现Runnable接口**:这是最常见的创建线程的方式,只需创建一个类实现`Runnable`接口,然后在`run()`方法中编写线程执行的代码。接着,通过`Thread`类的构造函数创建一个新的线程对象,将Runnable实例作为参数...

    【IT十八掌徐培成】Java基础第08天-01.多线程-yield.zip

    需要注意的是,`yield()`并不会像`sleep()`或`join()`那样使线程进入等待状态,而是让线程回到可运行状态,这意味着线程仍然可以随时被调度执行。 使用`yield()`的主要目的是提高线程的公平性,尤其是当有多个线程...

    JAVA多线程操作方法实用大全

    在上述示例中,`TestIsAlive`展示了如何使用`isAlive()`方法检查线程是否运行,而`TestInterrupt`演示了`sleep()`和`interrupt()`的用法。当`Thread.sleep()`被`interrupt()`打断时,`InterruptedException`会被抛出...

    这是一个线程类(Thread

    这三个方法用于线程间的通信,它们必须在`synchronized`代码块或方法中使用。`wait()`使当前线程等待,`notify()`唤醒一个等待的线程,`notifyAll()`唤醒所有等待的线程。 ### 5. 线程池与`ExecutorService` Java...

    Java 线程详解

    在 Java 中,线程的 join 方法可以让一个线程等待另外一个线程的执行完成。join 方法可以确保一个线程在另外一个线程执行完成后继续执行。 在 Java 中,线程的 sleep 方法可以让线程暂停执行一段时间。sleep 方法...

    多线程控制方法

    在 `main` 方法中,`frist.join()` 使得主线程等待 `frist` 线程执行完毕后再继续执行,这样可以确保先打印出 "First thread finishes running",再打印 "it is a long wait!"。同样,`second.join()` 用于等待 `...

    thread多线程学习记录

    Java提供了多种控制线程的方法,如start()启动线程,join()使当前线程等待指定线程结束后再继续执行,sleep()让线程暂停一段时间,yield()让当前线程暂停,让其他线程有机会执行,以及interrupt()中断线程。...

    JAVA线程高级-线程按序交替执行

    - `Thread.sleep()`方法可以使当前线程进入阻塞状态,到指定时间后自动恢复。 - `join()`方法让调用的线程等待目标线程执行完毕后再继续执行。 2. **`synchronized`关键字**: - `synchronized`用于实现线程同步...

    多线程使用操作大全

    - **方法**: `sleep()`、`join()`、`yield()`、`wait()`、`notify()` / `notifyAll()` - **功能**: - `sleep()`: 使当前线程暂停指定的时间。 - `join()`: 当前线程等待另一个线程结束。 - `yield()`: 让出CPU给...

    java中线程的简单处理

    `wait()`和`notify()`是`Object`类的方法,用于线程间通信,它们必须在`synchronized`代码块或方法中使用。`Lock`接口提供了更细粒度的锁控制,如`ReentrantLock`,比`synchronized`更灵活。 此外,`Thread.yield()...

    java多线程.pdf

    当线程启动时,会执行run方法中的代码,打印"Newthread"。主线程也会同时执行,打印"Mainthread"。可以看到,多线程的执行不是按照固定顺序,而是交替执行的,这取决于操作系统的线程调度机制。 实现Runnable接口也...

    Java线程 高级使用

    通过以上内容的学习,读者可以深入了解Java线程的高级使用方法,掌握如何在Java程序中高效地管理和控制线程,以及如何解决多线程环境下常见的问题。这对于开发高性能、高可用性的Java应用至关重要。

    java线程Thread的实例

    创建线程后,通过调用`start()`方法来启动它,这将执行`run()`方法中的代码。注意,不能直接调用`run()`,否则只会以单线程的方式执行,不会体现出多线程的特性。 ```java MyThread myThread = new MyThread(); ...

    Java线程.ppt

    `sleep()`方法让线程进入堵塞状态,`join()`方法等待线程执行完成,`yield()`方法让当前线程让出CPU,`stop()`方法停止线程(不推荐使用,因为可能引起数据不一致),`interrupt()`方法中断线程,以及`wait()`和`...

Global site tag (gtag.js) - Google Analytics