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的更多相关文章

  1. Java线程中yield与join方法的区别

    长期以来,多线程问题颇为受到面试官的青睐.虽然我个人认为我们当中很少有人能真正获得机会开发复杂的多线程应用(在过去的七年中,我得到了一个机会),但是理解多线程对增加你的信心很有用.之前,我讨论了一个w ...

  2. Java线程与多线程教程

    本文由 ImportNew - liken 翻译自 Journaldev.   Java线程是执行某些任务的轻量级进程.Java通过Thread类提供多线程支持,应用可以创建并发执行的多个线程. 应用 ...

  3. Java线程小刀牛试

    线程简介 什么是线程 现代操作系统调度的最小单元是线程,也叫轻量级进程(Light Weight Process),在一个进程里可以创建多个线程,这些线程都拥有各自的计数器.堆栈和局部变量等属性,并且 ...

  4. java 笔记(5) —— 线程,yield,join

    一.线程各个状态与转换: 新建状态:用new语句创建的线程对象处于新建状态,此时它和其它的java对象一样,仅仅在堆中被分配了内存 .就绪状态:当一个线程创建了以后,其他的线程调用了它的start() ...

  5. Java线程状态及 wait、sleep、join、interrupt、yield等的区别

    Java中的线程状态(详见Java线程状态及转换-MarchOn): wait:Object类的实例方法,释放CPU执行权,进入等待状态,直到  被中断.被拥有该对象锁的线程唤醒(notify或not ...

  6. java线程join方法使用方法简介

    本博客简介介绍一下java线程的join方法,join方法是实现线程同步,可以将原本并行执行的多线程方法变成串行执行的 如图所示代码,是并行执行的 public class ThreadTest { ...

  7. (Java多线程系列六)join()的用法和线程的优先级

    join()的用法和线程的优先级 1.join()的用法 join()作用就是让其他线程处于等待状态 先看一个需求:创建一个线程,子线程执行完毕后,主线程才能执行 public class JoinT ...

  8. java 多线程 Thread.join子线程结束父线程再运行;join(long):等待超时毫秒数

    Join的使用 目的:当子线程运行结束后,父线程才能再继续运行 /** * @ClassName ThreadJoinExample * @projectName: object1 * @author ...

  9. Java线程的概念

    1.      计算机系统 使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行:当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了. 缓 ...

  10. 【转载】 Java线程面试题 Top 50

    Java线程面试题 Top 50 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员 的欢迎.大多数待遇丰厚的J ...

随机推荐

  1. Ubuntu编译安装crtmp-server

    下载源码 从GitHub上下载:https://github.com/j0sh/crtmpserver.git 编译安装 apt-get install cmake apt-get install l ...

  2. oracle 登录数据库时报 无监听 的一种解决方式(监听日志文件达到4g默认上限)

    问题:登录服务器时 报无监听服务 检查步骤: 1.进入sqlplus查看数据库的状态,显示当前数据库的状态为OPEN 脚本:select status from v$Instance; 2.检查数据库 ...

  3. 时间复杂度O(n),空间复杂度O(1)解斐波那契数列

    #include <stdio.h> #include <iostream> using namespace std; long long fibs1(int in_iN) { ...

  4. python 环境搭建及pycharm的使用

    一.windows 1.上官网下载python3.5  https://www.python.org/downloads/ 2.安装的时候勾选path 3.安装完成后打开cmd 输入python查看安 ...

  5. IAAS-虚拟化技术组件介绍

    虚拟化技术组件涉及众多,下面对一些组件所处的层级以及定位做个简单的汇总介绍,部分信息来自于网络整理,如有不准确之处,请指正.

  6. pycharm中from xx import xx报错:Unresolved reference

    出现问题:无法引用到相关的类,但是这些类确实都在工程中 分析原因:import不成功是路径没对应上,pycharm默认该项目的根目录为source目录 解决方案: 将对应的项目searchTest,选 ...

  7. MySQL varchar类型数据转tinyint类型

    在mysql数据库中性别字段以前存的是'男'和'女',使用varchar类型存储的,但是在我mongo库中这个字段使用的是'1'和'0'存储的,在两个库之间的数据转换就很不方便,于是想要统一存储类型, ...

  8. ndarray数据类型

    dtype(数据类型)是一个特殊的对象,它含有ndarray将一块内存解释为特定数据类型所需的信息 In [18]: sim1 = np.array([1,2,3],dtype=np.float64) ...

  9. urllib使用

    1.基本方法 urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=Fals ...

  10. Java操作Memcached

    本文复制其他播客,有好的技术文章希望各位大神能告知... 谢谢. 如何使用Java操作Memcached实例: 代码一: package com.ghj.packageoftool; import j ...