在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. Kafka 学习笔记之 Topic日志清理

    Topic日志清理 server.properties: log.cleanup.policy=delete (默认) 1. 按时间维度进行Kafka日志清理 log.retention.hours= ...

  2. http post 请求,带参数,带请求头

    #!/usr/bin/env python # -*- coding: utf-8 -*- import requests import json url = 'http://............ ...

  3. DG常用运维命令及常见问题解决

    DG常见运维命令及常见问题解决方法 l> DG库启动.关闭标准操作Dataguard关闭1).先取消日志应用alter database recover managed standby data ...

  4. Springboot】Springboot整合邮件服务(HTML/附件/模板-QQ、网易)

    介绍 邮件服务是常用的服务之一,作用很多,对外可以给用户发送活动.营销广告等:对内可以发送系统监控报告与告警. 本文将介绍Springboot如何整合邮件服务,并给出不同邮件服务商的整合配置. 如图所 ...

  5. Comparable和Comparator 是什么以及区别

    一.Comparable和Comparator Comparable可以认为是一个内比较器,实现了Comparable接口的类,类的实例与实例直接可以比较,依赖compareTo方法的实现,compa ...

  6. python常用算法(5)——树,二叉树与AVL树

    1,树 树是一种非常重要的非线性数据结构,直观的看,它是数据元素(在树中称为节点)按分支关系组织起来的结构,很像自然界中树那样.树结构在客观世界中广泛存在,如人类社会的族谱和各种社会组织机构都可用树形 ...

  7. Win10安装虚拟机 + Ubuntu

    近期需要利用虚拟机,同时在虚拟机中安装Ubuntu系统.整理安装过程,供今后学习参考. 虚拟机安装包:VMware-workstation-full-12.1.0 链接:https://pan.bai ...

  8. scipy.misc.toimage()出现toimage报错

    scipy.misc.toimage()出现toimage报错 自己被这个问题困扰了许久,其实最后发现其实toimage这个函数已经被取消了,或者说是没有这个函数了.有了新得函数与之代替,那就是Ima ...

  9. PMP 德尔菲技术

    1.德尔菲技术,必须遵守以下几个规则: 每个专家只与主持人单线联系. 专家之间完全背靠背,更不能进行讨论.为保证专家提出独立见解,甚至需要把专家分散在不同的物理地点. 专家以匿名的书面形式提出意见. ...

  10. ‎Cocos2d-x 学习笔记(14.1) Event EventCustom EventListener

    1. Event EventCustom 所有事件类继承了Event. Event中的枚举,定义了事件的类型: enum class Type { TOUCH, //触摸 KEYBOARD, //键盘 ...