【java线程】的wait、sleep、join、yied
1.概述
使用Thread相对来说比较简单,没有什么成本,但是通常来说,我们使用线程基本就是覆写run方法,然后调用线程对象的start函数启动线程。
对于面试人员来说,这些都不是面试官会问到的问题,而线程的wait、sleep、join、yied这几个函数可问的就比较多了。
函数名 | 作用 |
wait |
当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去(释放)了对象的机锁,使得其他线程可以访问。用户可以使用notify、notifyAll或者指定睡眠时间来唤醒当前等待池中的线程。 注意:wait()、notify()、notifyAll()必须放在synchronized block中,否则会抛出异常 |
sleep | 该函数是Thread的静态函数,作用是使调用线程进入睡眠状态。因为sleep()是Thread类的Static方法,因此他不能改变对象的机锁。所以,当在一个Sychronized块中调用sleep()方法,线程虽然休眠了,但是对象的机锁并没有释放,其他线程无法访问这个对象(即使睡着也持有对象锁) |
join | 等待目标线程执行完成之后再继续执行 |
yield | 线程礼让。目标线程由运行状态转换为就绪状态,也就是让出执行权限,让其他线程得以优先执行,但其他线程能否优先执行是未知数 |
2.实际运用
(1)wait、notify
public class ThreadFunTest {
private static Object sLockObject = new Object(); static void waitAndNotifyAll() {
System.out.println("主线程运行");
Thread thread = new WaitThread();
thread.start();
long startTime = System.currentTimeMillis();
try {
synchronized (sLockObject) {
System.out.println("主线程等待");
sLockObject.wait();
}
} catch (Exception ignored) { }
long timsMs = (System.currentTimeMillis() - startTime);
System.out.println("主线程继续-->等待耗时:" + timsMs + "ms");
} static class WaitThread extends Thread {
@Override
public void run() {
try {
synchronized (sLockObject) {
Thread.sleep(3000);
sLockObject.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) {
ThreadFunTest.waitAndNotifyAll();
}
}
执行结果:
在waitAndNotifyAll()函数中,会启动一个WaitThread线程,在该线程中将会调用sleep函数睡眠3秒,线程启动后在主线程调用sLockObject的wait函数,使主线程进入等待状态,此时将不会继续执行。等WaitThread在run函数睡眠3秒后会调用sLockObject的notifyAll函数,此时就会重新唤醒正在等待中的主线程,因此会继续执行下去。
wait、notify机制通常用于等待机制的实现,当条件为满足时调用wait进入等待状态,一旦条件满足,调用notify或notifyAll唤醒等待的线程继续执行。
(2)join
与wait、sleep的浅显易懂不同的是join的作用并不那么直观,也许就是这个原因,使得join函数并不那么容易理解。join函数的原始解释为”Blocks the current Thread(Thread.currentThread())until the receiver finishes its execution and dies“,意思就是阻塞当前调用join函数时所在的线程,直到接收线程执行完毕后再继续。
static void joinDemo() {
Worker worker1 = new Worker("work-1");
Worker worker2 = new Worker("work-2");
worker1.start();
System.out.println("启动线程1");
try{
//调用work1的join函数,主线程会阻塞直到work1执行完成
worker1.join();
System.out.println("启动线程2");
//再启动线程2,并且调用线程2的join函数,主线程会阻塞直到worker2执行完成
worker2.start();
worker2.join();
}catch (Exception ignored){ }
System.out.println("主线程继续执行");
} static class Worker extends Thread {
public Worker(String name) {
super(name);
} @Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("work in " + getName());
}
} public static void main(String[] args) {
ThreadFunTest.joinDemo();
}
执行结果:
这是因为再joinDemo函数中,首先创建了两个子线程,然后启动了worker1,下一步再调用worker1的join函数。此时主线程进入阻塞状态,一直到worker1执行完毕后才开始继续执行。因为Worker的run函数会睡眠2秒,因此,在主线程中每次调用join实际上都会阻塞2秒,直到run执行完毕再继续。所以,上述逻辑为启动线程1--等待线程1执行完成--启动线程2--等待线程2执行完成--继续执行主干代码。
(3)yied
yied函数与join类似,官方解释为”Causes the calling Thread to yield execution time to another Thread that is read to run“。意思是使调用该函数的线程让出执行时间给其他已经就绪状态的线程。我们知道,线程的执行是有时间片的,每个线程轮流占用CPU固定的时间,执行周期到了之后就让出执行权给其他线程。而yield的功能就是主动让出线程的执行权给其他线程,其他线程能否得到优先执行就得看各个线程的状态了。示例:
static void yieldDemo() {
YieldThread t1 = new YieldThread("thread-1");
YieldThread t2 = new YieldThread("thread-2");
t1.start();
t2.start();
} static class YieldThread extends Thread {
public YieldThread(String name) {
super(name);
}
public synchronized void run() {
for (int i = 0; i < 5; i++) {
System.out.println(String.format("%s [%d] ---> %d", this.getName(), this.getPriority(), i));
//当i为2时调用当前线程的yield函数
if (i == 2) {
Thread.yield();
}
}
}
} public static void main(String[] args) {
ThreadFunTest.yieldDemo();
}
执行结果:
通常情况下t1首先执行,让t1的run函数执行到i等于2时让出当前线程的执行时间,因此,我们看到执行到的thread-2 等于2之前交替执行,等于2时,thread-2让出执行时间,执行thread-1,thread-1执行到2时又将执行权让出,执行thread-2直到完毕再开始执行thread-1.
调用yield就是让出当前线程的执行权,这样一来就王其他线程得到优先执行。
【java线程】的wait、sleep、join、yied的更多相关文章
- Java线程中yield与join方法的区别
长期以来,多线程问题颇为受到面试官的青睐.虽然我个人认为我们当中很少有人能真正获得机会开发复杂的多线程应用(在过去的七年中,我得到了一个机会),但是理解多线程对增加你的信心很有用.之前,我讨论了一个w ...
- Java线程与多线程教程
本文由 ImportNew - liken 翻译自 Journaldev. Java线程是执行某些任务的轻量级进程.Java通过Thread类提供多线程支持,应用可以创建并发执行的多个线程. 应用 ...
- Java线程小刀牛试
线程简介 什么是线程 现代操作系统调度的最小单元是线程,也叫轻量级进程(Light Weight Process),在一个进程里可以创建多个线程,这些线程都拥有各自的计数器.堆栈和局部变量等属性,并且 ...
- java 笔记(5) —— 线程,yield,join
一.线程各个状态与转换: 新建状态:用new语句创建的线程对象处于新建状态,此时它和其它的java对象一样,仅仅在堆中被分配了内存 .就绪状态:当一个线程创建了以后,其他的线程调用了它的start() ...
- Java线程状态及 wait、sleep、join、interrupt、yield等的区别
Java中的线程状态(详见Java线程状态及转换-MarchOn): wait:Object类的实例方法,释放CPU执行权,进入等待状态,直到 被中断.被拥有该对象锁的线程唤醒(notify或not ...
- java线程join方法使用方法简介
本博客简介介绍一下java线程的join方法,join方法是实现线程同步,可以将原本并行执行的多线程方法变成串行执行的 如图所示代码,是并行执行的 public class ThreadTest { ...
- (Java多线程系列六)join()的用法和线程的优先级
join()的用法和线程的优先级 1.join()的用法 join()作用就是让其他线程处于等待状态 先看一个需求:创建一个线程,子线程执行完毕后,主线程才能执行 public class JoinT ...
- java 多线程 Thread.join子线程结束父线程再运行;join(long):等待超时毫秒数
Join的使用 目的:当子线程运行结束后,父线程才能再继续运行 /** * @ClassName ThreadJoinExample * @projectName: object1 * @author ...
- Java线程的概念
1. 计算机系统 使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行:当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了. 缓 ...
- 【转载】 Java线程面试题 Top 50
Java线程面试题 Top 50 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员 的欢迎.大多数待遇丰厚的J ...
随机推荐
- 理解Python中的类对象、实例对象、属性、方法
class Animal(object): # 类对象 age = 0 # 公有类属性 __like = None # 私有类属性 def __init__(self): # 魔法方法 self.na ...
- 浅谈通信网络(三)——TCP/IP协议
简介 Transmission Control Protocol/Internet Protocol的简写,中译名为传输控制协议/因特网互联协议,又名网络通讯协议,是Internet最基本的协议.In ...
- Spring Data JPA 初体验
一,JPA相关的概念 JPA概述 全称是:JavaPersistence API.是SUN公司推出的一套基于ORM的规范. Hibernate框架中提供了JPA的实现. JPA通过JDK 5.0注解或 ...
- @EnableTransactionManagement注解理解
@EnableTransactionManagement表示开启事务支持,在springboot项目中一般配置在启动类上,效果等同于xml配置的<tx:annotation-driven /&g ...
- Vim手册
什么是 vim? Vim是从 vi 发展出来的一个文本编辑器.代码补完.编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用. 简单的来说, vi 是老式的字处理器,不过功能已经很齐全了,但是 ...
- Android的JDK、SDK、Eclipse的理解
今天看了这方面的内容,感觉学到了一些东西: 首先,jdk是用来处理Java语言的, sdk是用来处理Java语言和硬件之间的关联的, eclipse是用来编写Java语言的, 通过对这方面的理解,加深 ...
- Ubuntu系统下解决“YourUserName不在sudoers文件中。此事将被报告”的问题
本文由荒原之梦原创,原文链接:http://zhaokaifeng.com/?p=624 问题描述: 之前在使用Fedora系统时遇到过在使用 sudo 时提示"YourUserName不在 ...
- Spark2.1.0——Spark初体验
学习一个工具的最好途径,就是使用它.这就好比<极品飞车>玩得好的同学,未必真的会开车,要学习车的驾驶技能,就必须用手触摸方向盘.用脚感受刹车与油门的力道.在IT领域,在深入了解一个系统的原 ...
- 查找linux设备的uuid
[root@ ~]# blkid /dev/vdc /dev/vdc: UUID="bxxxx-xxx-41b9-8146-7da8bd645b92" TYPE="ext ...
- 基于开源 Openfire 聊天服务器 - 开发Openfire聊天记录插件
原文:http://www.cnblogs.com/hoojo/archive/2013/03/29/openfire_plugin_chatlogs_plugin_.html 随笔-150 评论- ...