例子

例1 最基础的等待-通知

下面一个例子,一个线程"waiting"在同步代码块调用了Object#wait()方法,另一个线程"timedWaiting"调用了Object#wait(3000)等待3000ms,主线程sleep 5000ms后唤醒所有线程。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j; /**
* @see Object#wait(long) 等待对应的毫秒数(不为0)或者被唤醒,执行后续代码
* @see Object#wait() 只有被唤醒(底层源码调用wait 0 ms)才能执行后续代码
* @author rhyme
* @date 2020/5/30 11:38
*/
@Slf4j
public class ObjectWaitMain {
private static final Object lock = new Object(); private static final Runnable waiting =
() -> {
synchronized (lock) {
try {
log.info("Thread: {}, will Object#wait()", Thread.currentThread().getName());
lock.wait();
log.info("Thread: {} is notified.", Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}; private static final Runnable timedWaiting =
() -> {
synchronized (lock) {
try {
log.info(
"Thread: {}, will be notified or wait 3000 milliseconds.",
Thread.currentThread().getName());
lock.wait(3000);
log.info(
"Thread: {}, after being notified or wait 3000 milliseconds.",
Thread.currentThread().getName()); } catch (InterruptedException e) {
e.printStackTrace();
}
}
}; public static void main(String[] args) throws InterruptedException { CompletableFuture.allOf(
CompletableFuture.runAsync(waiting), CompletableFuture.runAsync(timedWaiting)); // 主线程sleep5000ms,当3000ms后"timedWaiting"线程执行"wait(3000)"后的代码块
// 如果"timedWaiting"线程在3000ms被notify,那么会立即执行后续代码,不会wait 3000ms
TimeUnit.MILLISECONDS.sleep(5000); synchronized (lock) {
log.info("main will notifyAll waiting thread.");
lock.notifyAll();
}
log.info("main end.");
}
}

执行结果:

例2 Object#wait(long)的参数大于0与等于0

测试类代码

/**
* @author rhyme
* @date 2020/5/31 0:43
*/
@Slf4j
public class ThreadPoolExecutorTest {
private ThreadPoolExecutor threadPoolExecutor; @Before
public void initializeThreadPoolExecutor() {
threadPoolExecutor =
new ThreadPoolExecutor(4, 8, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(4));
} @After
public void teardown() throws InterruptedException {
threadPoolExecutor.shutdown(); TimeUnit.SECONDS.sleep(2);
threadPoolExecutor = null;
}

大于0

/**
* 当 {@link Object#wait(long)}的参数是大于0, 线程wait对象的毫秒数后, 不需被唤醒, 就可再次获取锁执行wait后续代码
* @see Object#wait(long)
*/
@Test
public void synchronizedTimedWaitingTest() {
Runnable timedWaiting =
() -> {
synchronized (this) {
while (true) {
try {
log.info("before Object#wait(1);");
this.wait(1);
log.info("after Object#wait(1);");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}; threadPoolExecutor.execute(timedWaiting);
}

执行结果:

等于0或Object#wait()

/**
* 当 {@link Object#wait(long)}的参数是0, 线程只能是被唤醒后, 才能再次获取锁执行wait后续代码
* @see Object#wait()
*/
@Test
public void synchronizedWaitingTest() {
Runnable timedWaiting =
() -> {
synchronized (this) {
while (true) {
try {
log.info("before Object#wait(0);");
// 与"this.wait()"等价
this.wait(0);
log.info("after Object#wait(0);");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}; threadPoolExecutor.execute(timedWaiting);
}

执行结果, 该线程一直wait, 线程池关闭结束, UT结束:

总结

Object#wait(long) 等待对应的毫秒数后(不为0)或者在等待过程中被唤醒后,就能再次获取锁执行wait后面代码;
Object#wait() 只有被唤醒后(底层源码调用wait 0 ms)才能再次获取锁执行wait后面代码。

源码如下:

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

Object#wait()与Object#wait(long)的区别的更多相关文章

  1. JavaScript中in操作符(for..in)、Object.keys()和Object.getOwnPropertyNames()的区别

    ECMAScript将对象的属性分为两种:数据属性和访问器属性.每一种属性内部都有一些特性,这里我们只关注对象属性的[[Enumerable]]特征,它表示是否通过 for-in 循环返回属性,也可以 ...

  2. Java中的Object、T(泛型)、?区别

    因为最近重新看了泛型,又看了些反射,导致我对Object.T(以下代指泛型).?产生了疑惑. 我们先来试着理解一下Object类,学习Java的应该都知道Object是所有类的父类,注意:那么这就意味 ...

  3. [转] JavaScript中in操作符(for..in)、Object.keys()和Object.getOwnPropertyNames()的区别

    ECMAScript将对象的属性分为两种:数据属性和访问器属性.每一种属性内部都有一些特性,这里我们只关注对象属性的[[Enumerable]]特征,它表示是否通过 for-in 循环返回属性,也可以 ...

  4. Java不定参数Object… obj 和 Object[] 的区别

    Java不定参数Object… obj 和 Object[] 的区别 简述: java中方法重载可以实现参数不同自动匹配对应方法.但现实中也存在这种问题.普通传参对于形如下面的方法,却显得臃肿而失优雅 ...

  5. instanceof和isInstance(Object obj) 和isAssignableFrom(Class cls)的区别和联系

    instanceof和isInstance(Object obj) 和isAssignableFrom(Class cls)的区别和联系          编程的时候可能会遇到一个不知道它属于哪个类的 ...

  6. or in 、Object.keys()以及Object.getOwnPropertyNames有什么区别?

    or in .Object.keys()以及Object.getOwnPropertyNames的区别 var obj= Object.create(parent, { b: { value: 2, ...

  7. host Object和native Object的区别

    Native Object: JavaScript语言提供的不依赖于执行宿主的对象,其中一些是内建对象,如:Global.Math:一些是在脚本运行环境中创建来使用的,如:Array.Boolean. ...

  8. 小tips:JS之for in、Object.keys()和Object.getOwnPropertyNames()的区别

    for..in循环 使用for..in循环时,返回的是所有能够通过对象访问的.可枚举的属性,既包括存在于实例中的属性,也包括存在于原型中的实例.这里需要注意的是使用for-in返回的属性因各个浏览器厂 ...

  9. typeof 和 Object.prototype.toString.call 数据类型判断的区别

    使用 typeof 来判断数据类型,只能区分基本类型,即 “number”,”string”,”undefined”,”boolean”,”object” 五种. 但 Object.prototype ...

随机推荐

  1. 入门大数据---Flume的搭建

    一.下载并解压到指定目录 崇尚授人以渔的思想,我说给大家怎么下载就行了,就不直接放连接了,大家可以直接输入官网地址 http://flume.apache.org ,一般在官网的上方或者左边都会有Do ...

  2. win10提示“无法设置移动热点 请打开WLAN”的解决方法

    一位用户在使用Win10创意者操作系统过程中,遇到了无法开启移动热点的情况,开关呈灰色状态,而且提示:无法设置移动热点 请打开WLAN,该如何解决呢?该用户表示Wlan一直开着呀,感觉非常奇怪.接下来 ...

  3. Java 内存回收机制

    当执行构造方法生成一个对象时,需要占用各种系统资源.当生成的对象不再使用时,就需要返回给操作系统,以免资源的泄露.在各种系统资源中,最常使用的就是内存.Java运行时系统通过垃圾收集周期性地释放无用对 ...

  4. 每日一题 - 剑指 Offer 30. 包含min函数的栈

    题目信息 时间: 2019-06-24 题目链接:Leetcode tag:栈 难易程度:简单 题目描述: 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 m ...

  5. 如何写出高性能的CSS3动画

    小伙伴们在写CSS3动画时,会发现在手机上很多时候会感到卡顿,然后Google到的解决方案大多是开启GPU加速transform: translate3d(0,0,0); 可解决,但是为什么开启GPU ...

  6. C# 基于内容电影推荐项目(一)

    从今天起,我将制作一个电影推荐项目,在此写下博客,记录每天的成果. 其实,从我发布 C# 爬取猫眼电影数据 这篇博客后, 我就已经开始制作电影推荐项目了,今天写下这篇博客,也是因为项目进度已经完成50 ...

  7. Django---进阶13

    目录 数据库表创建及同步 注册功能 登陆功能 bbs是一个前后端不分离的全栈项目,前端和后端都需要我们自己一步步的完成 表创建及同步 注册功能 forms组件 用户头像前端实时展示 ajax 登陆功能 ...

  8. day50 前端入门

    目录 一.引子 1 前端学习的历程 2 浏览器与http协议 2.1 浏览器窗口输入网址回车后发生了几件事 2.2 http协议 二.html入门 1 标签的分类 2 head内常用的标签 3 bod ...

  9. Jenkins+tomcat自动发布的热部署/重启及遇到的坑解决办法

    一.背景 公司的项目一直手动maven打包.上传服务器.关闭/开启tomcat,整个流程下来耗时耗力,虽然可以将所有流程通过shell脚本一次性解决,但如果可以通过idea的Jenkins插件一键自动 ...

  10. VulnHub::DC-1

    实验环境 一共有五个flag,有多种方法去提权,我们最终目标是去拿到/root的flag.总的来说,难度不高,适合新人练手 渗透过程 0x01 信息搜集 由于不知道靶机IP地址,进行D段扫描,获得靶机 ...