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()) 的相关文章

  • 在 Spring Boot 中重新加载/刷新缓存

    我正在使用 Spring Boot 对于缓存 我使用 Ehcache 到目前为止一切正常 但现在我必须重新加载 刷新 那么我该如何执行此操作 以便我的应用程序不会出现任何停机时间 我在Spring Ehcache中尝试了很多方法 但它不起作
  • 如何根据 JComboBox 选择动态地将控件添加到表单?

    我正在尝试使用 Swing 创建一个简单的 java 表单 这个想法的基本思想是用户将在 JComboBox 中选择 0 到 5 然后 通过 ItemStateChanged 侦听器 将动态添加几个面板 每个面板包含 4 个控件 因此 如果
  • 在游戏框架中编写功能测试的正确方法

    在为基于 play1 2 4 的 web 应用程序编写功能测试时 我对如何正确编码感到有点困惑 困惑在于所涉及的事务边界 我在某处读到每个测试都有自己的事务 在我的应用程序中 用户可以登录并向购物车添加一些商品 然后他可以提供一个地址 以便
  • 通过 JDBC 与 CLI 使用 MIT Kerberos 连接到 PostgreSQL 9.4 时出错

    我已经使用 MIT Kerberos 5 设置了 PostgreSQL 9 4 并且可以使用 psql 在 CLI 上连接 提交指纹后 我的委托人是 bgiles postgres REALM pg hba conf 有 host all
  • Java - 了解 PrintWriter 和刷新的需要

    好吧 首先我对所有代码表示歉意 但我觉得代码太多总比代码不够好 我正在制作一个简单的聊天客户端和印刷机 尤其是我正在努力解决的问题 使用现在的代码 它将与服务器类交互 并且完美地打印我想要打印的内容 但是 当我删除 writer flush
  • 从 Java 启动外部进程:stdout 和 stderr

    我正在使用标准从 java 启动一个外部进程java lang Process 我试图弄清楚该过程的输出是什么 但是采用结合了两者的格式stdout and stderr 目前 我有Process getInputStream它提供了访问s
  • 平衡括号问题的优化解

    给定一个仅包含字符的字符串 and 判断输入字符串是否有效 输入字符串在以下情况下有效 左括号必须由相同类型的括号封闭 左括号必须按正确的顺序关闭 请注意 空字符串也被视为有效 示例1 Input Output true Example 2
  • BigDecimal 中 Divide 方法的 Scale()

    new BigDecimal 37146555 53880000 divide new BigDecimal 1000000 scale 这返回10 但根据API divide method 返回一个 BigDecimal 其值为 这个 除
  • 使用用户名进行 Java LDAP 身份验证

    好吧 这让我发疯 我正在尝试使用 Java 创建 LDAP 身份验证 如果我在 SECURITY PRINCIPAL 中使用我的名字和姓氏 一切都很好 这是我的代码 try Hashtable
  • 读取 Nashorn JO4 和 NativeArray

    Java调用代码 import jdk nashorn api scripting myCustomHashMap dataStore new myCustomHashMap ScriptEngineManager sem new Scri
  • 从另一个类添加 Swing 组件

    我正在学习java 我正在尝试从另一个类向我的框架添加一个菜单栏 练习将代码划分为多个类以更好地组织程序 这是我的代码示例 public class MainApp public static void main String args C
  • 当用户使用相同的凭据登录两次时如何使用户会话无效

    我正在使用带有 Richfaces 和 Facelets 的 JSF 1 2 我有一个应用程序 其中包含许多会话范围的 Bean 和一些应用程序 Bean 假设用户使用 Firefox 登录 创建一个会话 ID A 然后他打开 Chrome
  • Android Studio 找不到 com.android.support:support-v4:19.1.0

    我已将一个项目导入Android Studio但我收到错误 找不到 com android support support v4 19 1 0 我在哪里可以找到这个文件 我已经使用导入了项目Gradle 我有Android Studio v
  • Android 上的自定义视图和窗口属性

    我想要做的是在我的应用程序顶部添加一个视图 该视图类似于过滤器视图 我想操纵屏幕的颜色 并且我还希望能够同时更改屏幕的亮度时间 这两件事似乎是分开起作用的 但不能一起起作用 这是我的代码 添加视图 colourView new Layer
  • 在 JSF 自定义验证器中区分 ajax 请求和完整请求

    我的验证器需要知道它是完整请求还是 ajax 请求 在我当前的解决方案中 我检查 http 请求标头X Requested With元素 public void validate FacesContext context UICompone
  • 添加和完成 PHP 源代码文档的工具 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我有几个已完成的较旧的 PHP 项目 其中有很多内容 我想以 javadoc phpDocumentor
  • Android 以编程方式停止 toast 通知?

    有没有办法以编程方式停止 Toast 消息 假设我有一个按钮 单击它可以滚动 toast 消息 并且在 onclick 事件中我想停止队列中的所有消息并只显示新消息 我该怎么做 我的代码的简化版本如下 代码 public class Hel
  • System.out.println("嗨"+6+10);打印Hi610?

    为什么要这样做 太令人困惑了 运算符优先级和结合性 两点 操作员 如果一个或两个参数都是字符串 则进行字符串连接 操作员 从左到右工作 所以在你的例子中 Hi 6 is Hi6 and Hi6 10 is Hi610 编辑 正如您在对另一个
  • 从 IntelliJ 运行 JavaFX 应用程序

    Versions openjdk版本 11 0 11 2021 04 20 OpenJDK 运行时环境 build 11 0 11 9 Ubuntu 0ubuntu2 20 10 OpenJDK 64 位服务器虚拟机 内部版本 11 0 1
  • 如何获取 res.drawable 文件夹的路径来复制文件?

    我正在编写我的应用程序AndroidStudio 我的里面有gif文件drawable gifs文件夹 我希望将该文件复制到MediaStore Images Media单击按钮后的文件夹 目前 即使使用发布的一些答案 我也无法获取我的 g

随机推荐

  • 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