在Java多线程编程中,Thread类是其中一个核心和关键的角色。因此,对该类中一些基础常用方法的理解和熟练使用是开发多线程代码的基础。本篇主要总结一下Thread中常用的一些静态方法的含义及代码中的使用。

sleep方法

源码如下:

    /**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds, subject to
* the precision and accuracy of system timers and schedulers. The thread
* does not lose ownership of any monitors.
*
* @param millis
* the length of time to sleep in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public static native void sleep(long millis) throws InterruptedException;

可以看到sleep是一个静态的本地方法,因为是本地方法,所以并没有java代码的实现,其实是调用了底层的C库函数来实现的睡眠。

有一个long类型的参数,表示睡眠多少毫秒。

阅读注释,sleep方法的含义就是,让当前正在执行任务的线程睡眠(临时地停止执行)指定的毫秒数,这个精度和准确性是用系统时钟和调度器保证的。但是,线程并不会释放它拥有的锁。

注意该方法会抛出InterruptedException中断异常。

sleep不会释放锁代码示例:

public class ThreadsleepDemo{

    private Object object = new Object();

    public static void main(String[] args) {

        ThreadsleepDemo threadsleepDemo = new ThreadsleepDemo();
Thread thread1 = threadsleepDemo.new SleepDemoThread();
thread1.setName("线程1");
Thread thread2 = threadsleepDemo.new SleepDemoThread();
thread2.setName("线程2");
thread1.start();
thread2.start(); } class SleepDemoThread extends Thread{
@Override
public void run() {
synchronized (object){
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}
}

输出结果如下:

线程1开始运行
线程1运行结束
线程2开始运行
线程2运行结束

可以多运行几次,可能会有线程1在上面或和线程2在上面,但始终都是一个行程运行完了才会运行另一个线程,中间不会插入进来一个线程运行。

yield方法

  /**
* A hint to the scheduler that the current thread is willing to yield
* its current use of a processor. The scheduler is free to ignore this
* hint.
*
* <p> Yield is a heuristic attempt to improve relative progression
* between threads that would otherwise over-utilise a CPU. Its use
* should be combined with detailed profiling and benchmarking to
* ensure that it actually has the desired effect.
*
* <p> It is rarely appropriate to use this method. It may be useful
* for debugging or testing purposes, where it may help to reproduce
* bugs due to race conditions. It may also be useful when designing
* concurrency control constructs such as the ones in the
* {@link java.util.concurrent.locks} package.
*/
public static native void yield();

当前线程对调度器的一个暗示,表示愿意让出CPU执行器的当前使用权,但是调度器可以自由忽略这个提示。

Yeild是一种在可能会过度使用一个CPU的多个线程之间提升相对进度试探性尝试。它的使用应该结合详细的性能分析和基准测试来进行,确保它确实有预期的效果。

很少使用这种方法。 它可能对调试或测试有用,可能有助于根据竞态条件重现错误。 在设计并发控制结构(例如java.util.concurrent.locks包中的并行控制结构)时也可能有用。

join方法

join有三个重载的方法

join()
join(long millis)
join(long millis,int nanoseconds)

主要看下第二个方法的源码

    /**
* Waits at most {@code millis} milliseconds for this thread to
* die. A timeout of {@code 0} means to wait forever.
*
* <p> This implementation uses a loop of {@code this.wait} calls
* conditioned on {@code this.isAlive}. As a thread terminates the
* {@code this.notifyAll} method is invoked. It is recommended that
* applications not use {@code wait}, {@code notify}, or
* {@code notifyAll} on {@code Thread} instances.
*/
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) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}

就是等待一个线程指定毫秒数后再消亡。无参数的join方法其实就是调用了join(0),即永远等待下去。不过通过源码我们可以看到,在while循环中有一个条件判断,即isAlive()方法,意思是如果当前线程还活着,就会一直等待下去。

有点懵,看个例子应该加深下理解。比如睡前想刷个抖音

刷抖音的工作我们交给一个线程来完成。

public class ScanDouyin extends Thread{

    // 浏览抖音的时长
private int scanTime; public ScanDouyin(String name, int scanTime){
super(name);
scanTime = this.scanTime;
}
@Override
public void run() {
System.out.println(getName() + ":开始刷抖音了");
try {
// 刷抖音的时间
sleep(scanTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() +":抖音刷完了,睡觉吧");
}
}

下面是准备睡觉的线程

/**
* 准备睡觉了,睡前想要刷个抖音
*/
public class ReadySleep extends Thread{ private ScanDouyin scanDouyin; public ReadySleep(String name,ScanDouyin scanDouyin){
super(name);
this.scanDouyin = scanDouyin;
}
@Override
public void run() {
System.out.println(getName() + ":准备开始睡觉啦");
try {
// 睡前刷把抖音
scanDouyin.join(); // 准备睡觉的具体内容
System.out.println("开始睡觉");
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + ":zzzzzzzz,已经睡着了");
} public static void main(String[] args) {
ScanDouyin scanDouyin = new ScanDouyin("刷抖音线程",10000);
ReadySleep readySleep = new ReadySleep("睡觉线程",scanDouyin);
readySleep.start();
scanDouyin.start(); }
}

输出结果如下:

睡觉线程:准备开始睡觉啦
刷抖音线程:开始刷抖音了
刷抖音线程:抖音刷完了,睡觉吧
开始睡觉
睡觉线程:zzzzzzzz,已经睡着了

这里我们我设置的刷抖音的时间是10s,睡觉线程的执行时间是100ms,也就是0.1s。

可以看到因为在睡觉线程中调用了刷抖音线程的join方法,使得睡觉的线程必须等待直到刷完抖音(刷抖音线程执行完毕,线程消亡),才能开始睡觉。

至此,应该可以明白,如果某个线程在另一个线程t上调用t.join(),此线程将被挂起,直到目标线程t结束才恢复(即t.isAlive()方法返回假)。

Java多线程中join、yield、sleep方法详解的更多相关文章

  1. Java并发编程基础--基本线程方法详解

    什么是线程 线程是操作系统调度的最小单位,一个进程中可以有多个线程,这些线程可以各自的计数器,栈,局部变量,并且能够访问共享的内存变量.多线程的优势是可以提高响应时间和吞吐量. 使用多线程 一个进程正 ...

  2. [ 转载 ] Java开发中的23种设计模式详解(转)

    Java开发中的23种设计模式详解(转)   设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类 ...

  3. Java提高篇——equals()与hashCode()方法详解

    java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...

  4. php_DWZ-JUI中碰到的问题解决方法详解(thinkphp+dwz)

    原文:php_DWZ-JUI中碰到的问题解决方法详解(thinkphp+dwz) 折腾了两天,dwz删除后,数据不能自动刷新,解决方案,直接看图  . 1. 删除.修改状态后无法刷新记录: 在dwz. ...

  5. python中requests库使用方法详解

    目录 python中requests库使用方法详解 官方文档 什么是Requests 安装Requests库 基本的GET请求 带参数的GET请求 解析json 添加headers 基本POST请求 ...

  6. PHP 中 16 个魔术方法详解

    PHP 中 16 个魔术方法详解   前言 PHP中把以两个下划线__开头的方法称为魔术方法(Magic methods),这些方法在PHP中充当了举足轻重的作用. 魔术方法包括: __constru ...

  7. 并发编程(六)Object类中线程相关的方法详解

    一.notify() 作用:唤醒一个正在等待该线程的锁的线程 PS : 唤醒的线程不会立即执行,它会与其他线程一起,争夺资源 /** * Object类的notify()和notifyAll()方法详 ...

  8. Java线程sleep,yield,join,wait方法详解

    1.sleep() 当一个线程调用sleep方法后,他就会放弃cpu,转到阻塞队列,sleep(long millis)方法是Thread类中的静态方法,millis参数设定线程睡眠的时间,毫秒为单位 ...

  9. java多线程同步以及线程间通信详解&消费者生产者模式&死锁&Thread.join()(多线程编程之二)

    本篇我们将讨论以下知识点: 1.线程同步问题的产生 什么是线程同步问题,我们先来看一段卖票系统的代码,然后再分析这个问题: package com.zejian.test; /** * @author ...

随机推荐

  1. mysql引号与esc键下方键

    navicat导出数据表发现建表语句如下: create table `product_category` ( `category_id` int not null auto_increment, ` ...

  2. VMware ESXI6.0服务器安装系列:U盘安装问题汇总之网卡驱动安装

    本文转载至:http://blog.51cto.com/huanwenli/1749298 在给物理服务器安装ESXI的过程中经常会遇到网卡驱动问题,如果是买的是Dell.HP.IBM等厂商的服务器, ...

  3. taro taroUi的H5打包后路径/修改为./

      打包文件路径修改在config/index.tsx中,如下 esnextModules: ['taro-ui'],配置也需要在h5中写入并且将publicPath: './'即可,不需要在做一个h ...

  4. opencv::Mat属性

    OpenCV支持JPG.PNG.TIFF等常见格式图像文件加载 加载图像 Mat imread( const String& filename, int flags = IMREAD_COLO ...

  5. linux使用jq工具解析json

    jq类似一个awk或grep一样的神器,可以方便地在命令行操作json 这里我使用海南万宁的天气接口做演示,地址:http://t.weather.sojson.com/api/weather/cit ...

  6. maven 打包 spring boot 生成docker 镜像

    1.所使用材料 ,spring boot 项目 基于maven ,maven 工具, docker工具 ps:为啥使用 docker 公司微服务需要启动太多,有两个优点吧! 1.方便管理,2.减少服务 ...

  7. 百万年薪python之路 -- 递归

    递归(每当有一个函数被递归调用,就应该要有一个返回值,才能正常把递归的返回值'归'回来) 一个正经的递归: ​ 1.不断调用自己本身 ​ 2.有明确的结束条件 递归注重于"一递 一归&quo ...

  8. .NET Framework概述

    1.NET Framework是为其运行的应用程序提供各种服务的托管执行环境,它包括两个主要组件:(1).公共语言运行时 (CLR),(2)..NET Framework 类库: 2.NET Fram ...

  9. 字符编码 + python2和python3的编码区别(day08整理)

    目录 昨日回顾 二十三.元组内置方法 二十四.散列表 二十五.字典内置方法 二十六.集合内置方法 二十七.深浅拷贝 拷贝 浅拷贝 深拷贝 今日内容 二十八.字符编码 1.文本编辑器存储信息的过程 2. ...

  10. OptimalSolution(1)--递归和动态规划(3)数组和字符串问题

    一.最长递增子序列(LIS) 给定数组arr,返回arr的最长递增子序列.例如,arr={2,1,5,3,6,4,8,9,7},返回的最长递增子序列为{1,3,4,5,8,9} 1.时间复杂度为O(N ...