美文网首页程序员Java-多线程Java Jni
Java 多线程中wait、notify、nptifyAll、y

Java 多线程中wait、notify、nptifyAll、y

作者: 夹胡碰 | 来源:发表于2020-12-21 00:52 被阅读0次

在Java多线程编程中,会涉及到wait、notify、nptifyAll、yield、join、sleep线程间交互的方法,这些比较晦涩难懂,现在全面介绍下这些方法的使用方式。

1. 总览

这些方法可大致分为两类,一类是继承自Object的方法,全部为native实现,一类是Thread的方法,也都是依托native实现的。

1) 继承自Object
  • notify()
  • notifyAll()
  • wait()
  • wait(long timeout)
  • wait(long timeout, int nanos)
2) Thread的方法
  • static yield()
  • static sleep(long millis)
  • static sleep(long millis, int nanos)
  • join(long millis)
  • join(long millis, int nanos)
  • join()

2. 线程状态转换

摘自 深入理解Java虚拟机 第三版 12章 Java内存模型与线程 461页

2.使用说明

1) wait/wait(time) 与 notify/notifyAll
  • wait、nofity、notifyAll都是操作synchronized锁持有对象的方法,wait表示当前锁对象开启wait等待通知唤醒并交出锁,notify表示通知唤醒一个wait状态的对象锁,notifyAll表示通知唤醒全部wait的对象锁。
  • wait、nofity、notifyAll都是配合synchronized使用的,只有锁持有对象才能使用这些方法,否则会报错。
  • wait表示一直阻塞,交出锁,wait(long timeout)表示到了设定时间,如果没有被notify通知唤醒,则自己自动继续执行,不过wait点之后的执行需要获取锁,这点要注意。

参考 Java wait和notify/notifyAll的使用方法

2) sleep

是Thread的static方法,可直接调用,表示当前线程睡眠指定时间。当线程睡眠时,会阻塞线程,交出cpu。(自行测试)

3) yield

是Thread的static方法,可直接调用,表示让出CPU资源,其他线程线程和自己重新竞争执行机会,不会阻塞线程。
该方法不能保证其他线程能争抢到,有可能还是自己抢到。

  • 代码样例
import java.time.LocalTime;

public class YieldTest {

    public static void main(String[] args) {
        Thread thread = new Thread(new MyThread());
        thread.start();

        Thread thread2 = new Thread(new MyThread());
        thread2.start();
    }

    public static class MyThread implements Runnable{

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + " " + i + " " + LocalTime.now());
                Thread.yield();
                System.out.println(Thread.currentThread().getName() + " " + i + " yield " + LocalTime.now());
            }
        }
    }
}
4) join/join(time)

join是成员方法,当前线程调用其他线程的join方法,形成阻塞,当调用的线程运行结束时,阻塞结束。
join(time)表示在设置时间内指定线程没有执行完,也结束阻塞,继续执行代码。

如下代码表示主线程调用了thread的join方法,形成阻塞,thread睡了2秒后,主线程继续执行。

  • 代码样例
import java.time.LocalTime;

public class JoinTest {

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new MyThread());
        thread.start();

        System.out.println("Main join wait " + LocalTime.now());
        thread.join();
        System.out.println("Main end " + LocalTime.now());
    }

    public static class MyThread implements Runnable{

        @Override
        public void run() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 输出
Main join wait 00:35:33.265
Main end 00:35:35.199
  • 源码解读
public final synchronized void join(long millis)
throws InterruptedException {
    long base = System.currentTimeMillis();
    long now = 0;

    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (millis == 0) {
        //无限等待至该线程可用死亡(!isAlive())
        //isAlive与wait都是native方法
        while (isAlive()) {
            wait(0); // 复用Object的wait方法
        }
    } else {
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

参考

  1. Java线程源码解析之yield和sleep

相关文章

网友评论

    本文标题:Java 多线程中wait、notify、nptifyAll、y

    本文链接:https://www.haomeiwen.com/subject/zeaknktx.html