Java暂停/挂起线程(suspend())和恢复线程(resume())

2023-05-16

暂停线程意味着此线程还可以恢复运行。在 Java 多线程中,可以使用 suspend() 方法暂停线程,使用 resume() 方法恢复线程的执行。

suspend() 与 resume() 方法

本节通过一个案例来介绍 suspend() 与 resume() 方法的用法。首先来看一下案例中使用到的 MyThread21 线程,代码如下所示。

package ch14;
public class MyThread21 extends Thread
{
    private long i=0;
    public long getI()
    {
        return i;
    }
    public void setI(long i)
    {
        this.i=i;
    }
    @Override
    public void run()
    {
        while(true)
        {
            i++;
        }
    }
}

MyThread21 线程中有一个成员 i,其中 setI() 方法和 getI() 方法分别用于设置和获取 i 的值,run() 方法则是一个从i开始递增的死循环。

下面编写主线程的代码,具体如下所示。

package ch14;
public class Test25
{
    public static void main(String[] args)
    {
        try
        {
            MyThread21 thread=new MyThread21();
            thread.start();
            Thread.sleep(5000);
            //A段
            thread.suspend();
            System.out.println("A= "+System.currentTimeMillis()+" i= "+thread.getI());
            Thread.sleep(5000);
            System.out.println("A= "+System.currentTimeMillis()+" i= "+thread.getI());
            //B段
            thread.resume();
            Thread.sleep(5000);
            //C段
            thread.suspend();
            System.out.println("B= "+System.currentTimeMillis()+" i= "+thread.getI());
            Thread.sleep(5000);
            System.out.println("B= "+System.currentTimeMillis()+" i= "+thread.getI());
        }
        catch(InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}

最终运行结果如下所示。


A= 1540978346179 i= 2680986095
A= 1540978351179 i= 2680986095
B= 1540978356179 i= 5348657508
B= 1540978361179 i= 5348657508  


从输出结果的时间来看,调用 suspend() 方法确实可以暂停线程,而在调用 resume() 方法后线程恢复运行状态。

独占问题

在使用 suspend() 方法与 resume() 方法时,如果使用不当极易造成公共的同步对象被独占,从而使得其他线程无法访问公共同步对象。

例 2

下面通过一个案例来演示这种情况。如下所示是案例中使用的公共对象的代码。

package ch14;
public class SynchronizedObject1
{
    synchronized public void printString()
    {
        System.out.println("begin");
        if (Thread.currentThread().getName().equals("a"))
        {
            System.out.println("a线程永远 suspend了!");
            Thread.currentThread().suspend();
        }
        System.out.println("end");
    }
}

SynchronizedObject1 类在 printString() 方法开始时输出“begin”,在该方法结束时输出“end”,方法体中的if判断如果当前线程的名称是 a 则调用 suspend() 方法暂停线程。

接下来编写主线程代码,在主线程中创建一个 SynchronizedObject1 类对象并在线程中调用 printString() 方法,具体代码如下所示。

package ch14;
public class Test26
{
    public static void main(String[] args)
    {
        try
        {
            final SynchronizedObject1 object=new SynchronizedObject1();
            Thread thread1=new Thread()
            {
                @Override
                public void run()
                {
                    object.printString();
                }
            };
            thread1.setName("a");
            thread1.start();
            Thread.sleep(1000);
            Thread thread2=new Thread()
            {
                @Override
                public void run()
                {
                    System.out.println("thread2启动了,但进入不了printString()方法!所以只会打印1个begin!");
                    System.out.println("因为printString()方法被a线程锁定并且永远暂停了!");
                    object.printString();
                }
            };
            thread2.start();
        }
        catch(InterruptedException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

上述代码比较简单这里就不再解释,运行后的结果如下所示。从中可以看到由于线程被永久暂停,所以只会输出一个 begin。


begin
a线程永远 suspend了!
thread2启动了,但进入不了printString()方法!所以只会打印1个begin!
因为printString()方法被a线程锁定并且永远暂停了!  

例 3

还有另外一种独占锁的情况也要格外注意,稍有不慎就会掉进“坑”里。创建测试用的 MyThread22 线程,具体代码如下:

package ch14;
public class MyThread22 extends Thread
{
    private long i=0;
    @Override
    public void run()
    {
        while (true)
        {
            i++;
        }
    }
}

再来看主线程的代码,如下所示。

package ch14;
public class Test27
{
    public static void main(String[] args)
    {
        try
        {
            MyThread22 thread=new MyThread22();
            thread.start();
            Thread.sleep(1000);
            thread.suspend();
            System.out.println("main end!");
        }
        catch(InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}

程序执行后将看到预料不到的结果,如下所示。


main end!

如果将 MyThread22 线程类的代码更改如下:  
package ch14;
public class MyThread22 extends Thread
{   
    private long i=0; 
    @Override 
    public void run()
    { 
        while(true)
        { 
            i++; 
            System.out.println(i); 
        } 
    }
}

再次运行程序,控制台将不打印 main end,运行结果如下所示。


......
130862
130863
130864
130865
130866
130867  


出现这种情况的原因是,当程序运行到 println() 方法内部停止时,同步锁未被释放。这导致当前 PrintStream 对象的 println() 方法一直呈“暂停”状态,并且“锁未释放”,而 main() 方法中的代码“System.out. println(Mmain end!'1);”迟迟不能执行打印。

提示:虽然 suspend() 方法是过期作废的方法,但还是有必要研究它过期作废的原因,这是很有意义的。

不同步问题

在使用 suspend() 方法与 resume() 方法时也容易出现因为线程的暂停而导致数据不同步的情况。

例 4

下面通过一个案例来演示这种情况。如下所示是案例中使用的公共对象的代码。

package ch14;
public class MyObject
{
    private String username="1";
    private String password="11";
    public void setValue(String u,String p)
    {
        this.username=u;
        if(Thread.currentThread().getName().equals("a"))
        {
            System.out.println("停止a线程!");
            Thread.currentThread().suspend();
        }
        this.password=p;
    }
    public void printUsernamePassword()
    {
        System.out.println(username+" "+password);
    }
}

如上述代码所示,MyObject 类的 setValue() 方法会在线程名称是 a 时执行停止线程操作。 如下所示是主线程代码。

package ch14;
public class Test28
{
    public static void main(String[] args) throws InterruptedException
    {
        final MyObject myobject=new MyObject();
        Thread thread1=new Thread()
        {
            public void run()
            {
                myobject.setValue("a","aa");
            };
        };
        thread1.setName("a");
        thread1.start();
        Thread.sleep(500);
        Thread thread2=new Thread()
        {
            public void run()
            {
                myobject.printUsernamePassword();
            };
        };
        thread2.start();
    }
}

程序运行结果如下所示。


停止a线程!
a 11  

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java暂停/挂起线程(suspend())和恢复线程(resume()) 的相关文章

  • Java 中等效的并行扩展

    我在 Net 开发中使用并行扩展有一些经验 但我正在考虑在 Java 中做一些工作 这些工作将受益于易于使用的并行库 JVM 是否提供任何与并行扩展类似的工具 您应该熟悉java util concurrent http java sun
  • 如何使用 Java 和 Selenium WebDriver 在 C 目录中创建文件夹并需要将屏幕截图保存在该目录中?

    目前正在与硒网络驱动程序和代码Java 我有一种情况 我需要在 C 目录中创建一个文件夹 并在该文件夹中创建我通过 selenium Web 驱动程序代码拍摄的屏幕截图 它需要存储在带有时间戳的文件夹中 如果我每天按计划运行脚本 所有屏幕截
  • 如何在 Play java 中创建数据库线程池并使用该池进行数据库查询

    我目前正在使用 play java 并使用默认线程池进行数据库查询 但了解使用数据库线程池进行数据库查询可以使我的系统更加高效 目前我的代码是 import play libs Akka import scala concurrent Ex
  • 在画布上绘图

    我正在编写一个 Android 应用程序 它可以在视图的 onDraw 事件上直接绘制到画布上 我正在绘制一些涉及单独绘制每个像素的东西 为此我使用类似的东西 for int x 0 x lt xMax x for int y 0 y lt
  • 制作一个交互式Windows服务

    我希望我的 Java 应用程序成为交互式 Windows 服务 用户登录时具有 GUI 的 Windows 服务 我搜索了这个 我发现这样做的方法是有两个程序 第一个是服务 第二个是 GUI 程序并使它们进行通信 服务将从 GUI 程序获取
  • 多个 Maven 配置文件激活多个 Spring 配置文件

    我想在 Maven 中构建一个环境 在其中我想根据哪些 Maven 配置文件处于活动状态来累积激活多个 spring 配置文件 目前我的 pom xml 的相关部分如下所示
  • 加速代码 - 3D 数组

    我正在尝试提高我编写的一些代码的速度 我想知道从 3d 整数数组访问数据的效率如何 我有一个数组 int cube new int 10 10 10 我用价值观填充其中 然后我访问这些值数千次 我想知道 由于理论上所有 3d 数组都存储在内
  • Spark 1.3.1 上的 Apache Phoenix(4.3.1 和 4.4.0-HBase-0.98)ClassNotFoundException

    我正在尝试通过 Spark 连接到 Phoenix 并且在通过 JDBC 驱动程序打开连接时不断收到以下异常 为简洁起见 下面是完整的堆栈跟踪 Caused by java lang ClassNotFoundException org a
  • 控制Android的前置LED灯

    我试图在用户按下某个按钮时在前面的 LED 上实现 1 秒红色闪烁 但我很难找到有关如何访问和使用前置 LED 的文档 教程甚至代码示例 我的意思是位于 自拍 相机和触摸屏附近的 LED 我已经看到了使用手电筒和相机类 已弃用 的示例 但我
  • 反射找不到对象子类型

    我试图通过使用反射来获取包中的所有类 当我使用具体类的代码 本例中为 A 时 它可以工作并打印子类信息 B 扩展 A 因此它打印 B 信息 但是当我将它与对象类一起使用时 它不起作用 我该如何修复它 这段代码的工作原理 Reflection
  • 斯坦福 NLP - 处理文件列表时 OpenIE 内存不足

    我正在尝试使用斯坦福 CoreNLP 中的 OpenIE 工具从多个文件中提取信息 当多个文件 而不是一个 传递到输入时 它会给出内存不足错误 All files have been queued awaiting termination
  • 十进制到八进制的转换[重复]

    这个问题在这里已经有答案了 可能的重复 十进制转换错误 https stackoverflow com questions 13142977 decimal conversion error 我正在为一个类编写一个程序 并且在计算如何将八进
  • 如何从终端运行处理应用程序

    我目前正在使用加工 http processing org对于一个小项目 但是我不喜欢它附带的文本编辑器 我使用 vim 编写所有代码 我找到了 pde 文件的位置 并且我一直在从 vim 中编辑它们 然后重新打开它们并运行它们 重新加载脚
  • 在mockito中使用when进行模拟ContextLoader.getCurrentWebApplicationContext()调用。我该怎么做?

    我试图在使用 mockito 时模拟 ContextLoader getCurrentWebApplicationContext 调用 但它无法模拟 here is my source code Mock org springframewo
  • 如何在桌面浏览器上使用 webdriver 移动网络

    我正在使用 selenium webdriver 进行 AUT 被测应用程序 的功能测试自动化 AUT 是响应式网络 我几乎完成了桌面浏览器的不同测试用例 现在 相同的测试用例也适用于移动浏览器 因为可以从移动浏览器访问 AUT 由于它是响
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • JGit 检查分支是否已签出

    我正在使用 JGit 开发一个项目 我设法删除了一个分支 但我还想检查该分支是否已签出 我发现了一个变量CheckoutCommand但它是私有的 private boolean isCheckoutIndex return startCo
  • java.lang.IllegalStateException:驱动程序可执行文件的路径必须由 webdriver.chrome.driver 系统属性设置 - Similiar 不回答

    尝试学习 Selenium 我打开了类似的问题 但似乎没有任何帮助 我的代码 package seleniumPractice import org openqa selenium WebDriver import org openqa s
  • 节拍匹配算法

    我最近开始尝试创建一个移动应用程序 iOS Android 它将自动击败比赛 http en wikipedia org wiki Beatmatching http en wikipedia org wiki Beatmatching 两
  • Spring Boot @ConfigurationProperties 不从环境中检索属性

    我正在使用 Spring Boot 1 2 1 并尝试创建一个 ConfigurationProperties带有验证的bean 如下所示 package com sampleapp import java net URL import j

随机推荐

  • RxJava2源码分析——Map操作符

    本文章用的RxJava和RxAndroid版本如下 xff1a implementation 39 io reactivex rxjava2 rxjava 2 2 6 39 implementation 39 io reactivex rx
  • 交叉编译pytorch的aarch64版本

    提示 xff1a 文章写完后 xff0c 目录可以自动生成 xff0c 如何生成可参考右边的帮助文档 文章目录 前言一 基础环境二 编译流程1 下载源码并配置TOOLCHAIN FILE内容2 预编译出protoc库和sleef库3 ana
  • 使用CSplitterWnd类静态分割的窗口的隐藏[转]

    标题略长 之前百度了很多 xff0c 也看过了很多程序 xff0c 那个时候稍微有点小青涩 xff0c 所以那些东西根本是看不懂什么意思 现在回过头来看 xff0c 其实还是很容易就实现的 当然 xff0c 话题很初级 xff0c 不是面向
  • Rxjava2源码-FlatMap操作符

    先来看一下使用demo Observable create new ObservableOnSubscribe lt String gt 64 Override public void subscribe ObservableEmitter
  • 代理设计模式

    代理模式的结构与实现 代理模式的结构比较简单 xff0c 主要是通过定义一个继承抽象主题的代理来包含真实主题 xff0c 从而实现对真实主题的访问 xff0c 下面来分析其基本结构和实现方法 1 模式的结构 代理模式的主要角色如下 抽象主题
  • 适配器模式

    模式的结构与实现 类适配器模式可采用多重继承方式实现 xff0c 如 C 43 43 可定义一个适配器类来同时继承当前系统的业务接口和现有组件库中已经存在的组件接口 xff1b Java 不支持多继承 xff0c 但可以定义一个适配器类来实
  • 装饰器模式

    装饰器模式的结构与实现 通常情况下 xff0c 扩展一个类的功能会使用继承方式来实现 但继承具有静态特征 xff0c 耦合度高 xff0c 并且随着扩展功能的增多 xff0c 子类会很膨胀 如果使用组合关系来创建一个包装对象 xff08 即
  • 享元设计模式

    享元模式的结构与实现 享元模式的定义提出了两个要求 xff0c 细粒度和共享对象 因为要求细粒度 xff0c 所以不可避免地会使对象数量多且性质相近 xff0c 此时我们就将这些对象的信息分为两个部分 xff1a 内部状态和外部状态 内部状
  • 组合设计模式

    组合模式的结构与实现 组合模式的结构不是很复杂 xff0c 下面对它的结构和实现进行分析 1 模式的结构 组合模式包含以下主要角色 抽象构件 xff08 Component xff09 角色 xff1a 它的主要作用是为树叶构件和树枝构件声
  • 模板方法模式

    模式的结构与实现 模板方法模式需要注意抽象类与具体子类之间的协作 它用到了虚函数的多态性技术以及 不用调用我 xff0c 让我来调用你 的反向控制技术 现在来介绍它们的基本结构 1 模式的结构 模板方法模式包含以下主要角色 1 xff09
  • 策略设计模式

    策略模式的结构与实现 策略模式是准备一组算法 xff0c 并将这组算法封装到一系列的策略类里面 xff0c 作为一个抽象策略类的子类 策略模式的重心不是如何实现算法 xff0c 而是如何组织这些算法 xff0c 从而让程序结构更加灵活 xf
  • 命令设计模式

    命令模式的结构与实现 可以将系统中的相关操作抽象成命令 xff0c 使调用者与实现者相关分离 xff0c 其结构如下 1 模式的结构 命令模式包含以下主要角色 抽象命令类 xff08 Command xff09 角色 xff1a 声明执行命
  • 状态设计模式

    状态模式的结构与实现 状态模式把受环境改变的对象行为包装在不同的状态对象里 xff0c 其意图是让一个对象在其内部状态改变的时候 xff0c 其行为也随之改变 现在我们来分析其基本结构和实现方法 1 模式的结构 状态模式包含以下主要角色 环
  • linux开启关闭端口(iptables 无法使用情况下)

    一 查看端口开启状态 查询已开放的端口 netstat anp root 64 localhost etc firewall cmd query port 61 8080 tcp 提示 yes xff0c 表示开启 xff1b no表示未开
  • 中介者模式

    模式的结构与实现 中介者模式实现的关键是找出 中介者 xff0c 下面对它的结构和实现进行分析 1 模式的结构 中介者模式包含以下主要角色 抽象中介者 xff08 Mediator xff09 角色 xff1a 它是中介者的接口 xff0c
  • YUV解析

    一般的视频采集芯片输出的码流一般都是 YUV 格式数据流 xff0c 后续视频处理也是对 YUV 数据流进行编码和解析 所以 xff0c 了解 YUV 数据流对做视频领域的人而言 xff0c 至关重要 在介绍 YUV 格式之前 xff0c
  • Android Camera旋转角度

    首先理解一下 info orientation 官方解释 官方定义 xff1a orientation 表示相机图像的方向 它的值是相机图像顺时针旋转到设备自然方向一致时的角度 例如假设设备是竖屏的 后置相机传感器是横屏安装的 当你面向屏幕
  • NV21 图像旋转处理 ( 后置摄像头顺时针旋转 90 度 | 前置摄像头顺时针旋转 90 度 )

    1 NV21 格式图像数据的排列 16 1616 个 Y 灰度数据在前 然后 4 44 组 8 88 个 VU 色彩值 饱和度 数据交替存放 2 NV21 格式的图像的 YUV 值顺时针旋转 90 度后的 YUV 矩阵为 3 灰度值 Y 数
  • enum 实现 Parcelable 接口

    enum 实现 Parcelable 接口 当你创建一个枚举 xff0c 想要使用上述插件时 xff0c 就会发现无法序列号 这个是因为 Parcel writeXXX 没有写入枚举的方法 xff0c 所以无法直接实现 Parcelable
  • Java暂停/挂起线程(suspend())和恢复线程(resume())

    暂停线程意味着此线程还可以恢复运行 在 Java 多线程中 xff0c 可以使用 suspend 方法暂停线程 xff0c 使用 resume 方法恢复线程的执行 suspend 与 resume 方法 本节通过一个案例来介绍 suspen