多线程编程之如何暂停与恢复线程

简介: 前面的文章多线程编程之停止线程的几种方法介绍了停止线程运行的三种方法:

1 前言


前面的文章多线程编程之停止线程的几种方法介绍了停止线程运行的三种方法:


1、使用退出标志,使线程正常退出;


2、使用stop方法强制结束线程,该方法因为不安全已经被废弃;


3、使用interrupt方法中断线程。


在多线程编程中除了通过上述方法停止线程,还可以使用一些方法暂停正在运行中的线程。如果暂停线程可以使用suspend方法,暂停线程意味着可以恢复运行,重启暂停线的线程可以使用resume方法。但是这两个方法和stop方法一样都是过期作废的方法。


2 正文


先通过一个例子看看suspend方法和resume方法的使用:


/**
 * resume方法和suspend方法的使用
 * author:jiangxia
 * date:2021-04-16
 */
public class Demo19 {
    public static void main(String[] args) throws InterruptedException {
        Thread19 t = new Thread19();
        //使用start方法启动线程
        t.start();
        Thread.sleep(1000);
        //该resume方法同样已经被舍弃方法同样已经舍弃
        t.suspend();//暂停线程
        System.out.println("Time1="+System.currentTimeMillis()+";i="+t.getI());
        Thread.sleep(1000);
        System.out.println("Time1="+System.currentTimeMillis()+";i="+t.getI());
        //恢复暂停的线程
        //resume方法同样已经被舍弃
        t.resume();
        Thread.sleep(1000);
        t.suspend();
        System.out.println("Time2="+System.currentTimeMillis()+";i="+t.getI());
        Thread.sleep(1000);
        System.out.println("Time2="+System.currentTimeMillis()+";i="+t.getI());
    }
}
class  Thread19 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++;
        }
    }
}
复制代码


91147e759a9c4b1d94a29c04bac075b5~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


虽然现在已经成功的暂停和恢复了线程,但是我们会发现 suspend 和 resume 早已被标注为了废弃方法,并且不推荐使用了。IDEA编辑器删除线显示:


dccbb697203d4cd19b97e6905e55424e~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


那么为什么会被弃用呢?


肯定是在功能上有缺陷。这个缺陷就是不释放锁。如果调用了 suspend 方法的目标线程在挂起时对某一重要的系统资源持有锁,那么在目标线程重新开始之前其他任何线程都无法访问该资源。


/**
 * resume方法和suspend方法的使用
 * author:jiangxia
 * date:2021-04-16
 */
public class Demo20 {
    public static void main(String[] args) throws InterruptedException {
        Demo20Service demo20Service = new Demo20Service();
        Thread t1 = new Thread(){
            @Override
            public void run() {
                demo20Service.printInfo();
            }
        };
        t1.setName("A");
        t1.start();
        Thread.sleep(10);
        //因为A线程暂停了,所以t2线程不运行
        Thread t2 = new Thread(){
            @Override
            public void run() {
                demo20Service.printInfo();
            }
        };
        t2.start();
    }
}
class Demo20Service{
    //对该方法加synchronized关键字
    synchronized public void printInfo(){
        System.out.println("线程开始");
        //如果线程名为A,暂停线程
        if("A".equals(Thread.currentThread().getName())){
            System.out.println("A线程suspend");
            Thread.currentThread().suspend();
        }
        System.out.println("线程结束");
    }
}
复制代码


4cdff06e984749159edaf1825eb060d3~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


另外还需要注意关于System.out.print()的同步。suspend下println方法不会释放同步锁,程序运行到println方法内部时,同步锁没有被释放,导致当前的PrintStream对象的println方法一直呈『暂停』状态。


/**
 * suspend的print问题
 * author:jiangxia
 * date:2021-04-16
 */
public class Demo21 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Demo21Thread();
        thread.start();
        Thread.sleep(100);
        thread.suspend();
        System.out.println("main线程结束");
    }
}
class Demo21Thread extends Thread{
    private long i=0;
    @Override
    public void run() {
        while (true){
            i++;
            System.out.println("i="+i);
        }
    }
}
复制代码


5b18b317cfe14de88fa8d94e822e1835~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


可以发现结果到最后都不会打印main线程结束。println的源码如下:


public void println(String x) {
        synchronized (this) {
            print(x);
            newLine();
        }
    }
复制代码


因为println方法是一个同步方法,所以线程suspend之后没有释放锁。


另一个缺陷就是不同步。使用 suspend 和 resume 方法也容易出现因为线程的暂停而导致数据不同步的问题。比如:


package com.jiangxia.chap1;
/**
 * suspend和resume导致数据不同步的问题
 * author:jiangxia
 * date:2021-04-16
 */
public class Demo22 {
    public static void main(String[] args) throws InterruptedException {
        Demo22User user = new Demo22User();
        Thread t1 = new Thread(){
            @Override
            public void run() {
                user.updateUser("貂蝉", "女");
            }
        };
        t1.setName("A");
        t1.start();
        Thread.sleep(10);
        Thread t2 = new Thread(){
            @Override
            public void run() {
                user.printUserInfo();
            }
        };
        t2.start();
    }
}
class Demo22User {
    private String name = "吕布";
    private String gen = "男";
    public void updateUser(String name, String gen){
        this.name = name;
        if ("A".equals(Thread.currentThread().getName())){
            System.out.println("停止A线程");
            Thread.currentThread().suspend();
        }
        this.gen = gen;
    }
    public void printUserInfo(){
        System.out.println("姓名=" + name + ", 性别=" +gen);
    }
}
复制代码


6012e9ecc98f43f4ab732b67a837570d~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


可以发现本应输出的是貂蝉女,结果输出的是貂蝉男。程序运行的结果出现了不同步的情况。


3 总结


suspend()方法可以暂停线程,而且不会释放同步锁,而且暂停不会导致睡眠时间的延长;


resume()可以使线程恢复状态,而且会继续执行暂停前的剩余代码。


但是上面两个方法都是过期作废的方法,所以不推荐使用。

目录
相关文章
|
1月前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
168 2
|
1月前
|
NoSQL Redis
单线程传奇Redis,为何引入多线程?
Redis 4.0 引入多线程支持,主要用于后台对象删除、处理阻塞命令和网络 I/O 等操作,以提高并发性和性能。尽管如此,Redis 仍保留单线程执行模型处理客户端请求,确保高效性和简单性。多线程仅用于优化后台任务,如异步删除过期对象和分担读写操作,从而提升整体性能。
67 1
|
2月前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
2月前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
1月前
|
缓存 Java 调度
多线程编程核心:上下文切换深度解析
在现代计算机系统中,多线程编程已成为提高程序性能和响应速度的关键技术。然而,多线程编程中一个不可避免的概念就是上下文切换(Context Switching)。本文将深入探讨上下文切换的概念、原因、影响以及优化策略,帮助你在工作和学习中深入理解这一技术干货。
54 10
|
1月前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
1月前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
66 3
|
1月前
|
算法 调度 开发者
多线程编程核心:上下文切换深度解析
在多线程编程中,上下文切换是一个至关重要的概念,它直接影响到程序的性能和响应速度。本文将深入探讨上下文切换的含义、原因、影响以及如何优化,帮助你在工作和学习中更好地理解和应用多线程技术。
50 4
|
28天前
|
安全 Java API
【JavaEE】多线程编程引入——认识Thread类
Thread类,Thread中的run方法,在编程中怎么调度多线程
|
2月前
|
安全 Java 开发者
Java中的多线程编程:从基础到实践
本文深入探讨了Java多线程编程的核心概念和实践技巧,旨在帮助读者理解多线程的工作原理,掌握线程的创建、管理和同步机制。通过具体示例和最佳实践,本文展示了如何在Java应用中有效地利用多线程技术,提高程序性能和响应速度。
78 1

相关实验场景

更多