前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >线程的停止与暂停

线程的停止与暂停

作者头像
全栈程序员站长
发布于 2022-09-06 08:12:28
发布于 2022-09-06 08:12:28
5.7K00
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

1.停止线程

    停止线程不像停止一个循环break一样干脆。

  停止一个线程意味着在线程处理完任务之前停掉正在做的操作,也就是放弃当前的操作。虽然看起来简单,但是必须做好正确的防范措施,以便达到预期的效果。停止一个线程可以用Thread.stop(),但最好不要用它。虽然它确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且已经作废的方法。

  大多数停止一个线程用Thread.interrupt()方法,尽管方法的名称是”中止,停止”的意思,但这个方法不一定会停止一个正在运行的线程,还需要加入一个判断才可以完成线程的停止。

 在Java中有3种方法可以停止正在运行的线程:

  (1)使用退出标志使线程正常终止,也就是当run方法完成后线程终止。

  (2)使用stop方法强行终止线程,但是不推荐使用这个方法,因为stop和suspend、resume一样,都是过期作废的方法。

  (3)使用interrupt方法中断线程。

1.停止不了的线程  

  调用thread.interrupt()方法,但是此方法并不会马上停止线程,只是在当前线程打了一个停止的标记,并不是真正的停止线程。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.qlq.thread.three;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo1 extends Thread {

    private static final Logger log = LoggerFactory.getLogger(Demo1.class);

    @Override
    public void run() {
        for (int i = 0; i < 50;) {
            log.debug("i->{}", i++);
        }
    }

    public static void main(String[] args) {
        try {
            Demo1 demo1 = new Demo1();
            demo1.start();
            Thread.sleep(200);
            // 发出中断线程信号
            demo1.interrupt();
        } catch (InterruptedException e) {
            log.error("main catch ", e);
        }

    }
}

结果:(仍然会执行完线程的run方法,也就是interrupt()方法并没有中断线程)

2.判断线程是否终止

  在Java的SDK种,提供了两个方法判断线程是否终止:

(1)this.interrupted(),测试当前线程是否已经中止 (静态方法——测试当前线程是否已经是中断状态,执行后具有将状态标志清除为false的功能)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

(2)this.isInterrupted(),测试线程是否已经中断。(实例方法—–测试线程对象Thread对象是否已经是中断状态,但不清除状态标志)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public boolean isInterrupted() {
        return isInterrupted(false);
    }

可以看出上面两个方法都调用了isInterrupted(boolean)方法,查看源码:(参数是是否重置状态)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /**
     * Tests if some Thread has been interrupted.  The interrupted state
     * is reset or not based on the value of ClearInterrupted that is
     * passed.
     */
    private native boolean isInterrupted(boolean ClearInterrupted);
  • this.interrupted()静态方法的研究–执行任何线程的此方法都相当于执行Thread.currentThread.interrupted(),会返回线程的中断状态并且会清除中断状态

    测试当前线程是否已经中断,当前线程是指运行this.interrupted()方法的线程。

测试代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.qlq.thread.three;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo2 extends Thread {

    private static final Logger log = LoggerFactory.getLogger(Demo2.class);

    @Override
    public void run() {
        for (int i = 0; i < 5000000;) {
        }
    }

    public static void main(String[] args) {
        try {
            Demo2 demo2 = new Demo2();
            demo2.start();
            Thread.sleep(1000);
            // 发出中断线程信号
            demo2.interrupt();
            log.debug("是否停止1?{}", demo2.interrupted());
            log.debug("是否停止2?{}", demo2.interrupted());
        } catch (InterruptedException e) {
            log.error("main catch ", e);
        }
        log.debug("end");
    }
}

结果:

2018-12-07 [cn.qlq.thread.three.Demo2]-[DEBUG] 是否停止1?false 2018-12-07 [cn.qlq.thread.three.Demo2]-[DEBUG] 是否停止2?false 2018-12-07 [cn.qlq.thread.three.Demo2]-[DEBUG] end

解释:虽然调用的是demo2.interrupted()方法,但是我们从源码也可以看出测的是当前线程,当前线程就是执行当前代码的线程,也就是main线程,所以打印了两个false。

如何测试main线程的中断效果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.qlq.thread.three;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo3 extends Thread {

    private static final Logger log = LoggerFactory.getLogger(Demo3.class);

    public static void main(String[] args) {
        Thread.currentThread().interrupt();
        // 发出中断线程信号
        log.debug("是否停止1?{}", Thread.interrupted());
        log.debug("是否停止2?{}", Thread.interrupted());
    }
}

结果:

2018-12-07 [cn.qlq.thread.three.Demo3]-[DEBUG] 是否停止1?true 2018-12-07 [cn.qlq.thread.three.Demo3]-[DEBUG] 是否停止2?false

第二个参数是返回值是false的原因?官网对此方法的解释:

  测试当前线程是否已经中断(当前线程是指执行当前代码的线程)。线程的中断状态由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回false(在第一次调用已清除了其中状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。

  解释已经很清楚了,interrupted()方法具有清除状态的功能,所以第二次调用返回的是false。

  • isInterrupyed()方法的研究—–检测线程对象是否中断的状态,并且不会清除状态。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.qlq.thread.three;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo5 extends Thread {

    private static final Logger log = LoggerFactory.getLogger(Demo5.class);

    @Override
    public void run() {
        for (int i = 0; i < 5000000;) {
        }
    }

    public static void main(String[] args) {
        try {
            Demo5 demo2 = new Demo5();
            demo2.start();
            Thread.sleep(1000);
            // 发出中断线程信号
            log.debug("是否停止0?{}", demo2.isInterrupted());
            demo2.interrupt();
            log.debug("是否停止1?{}", demo2.isInterrupted());
            log.debug("是否停止2?{}", demo2.isInterrupted());
        } catch (InterruptedException e) {
            log.error("main catch ", e);
        }
        log.debug("end");
    }
}

结果:

2018-12-07 [cn.qlq.thread.three.Demo5]-[DEBUG] 是否停止0?false 2018-12-07 [cn.qlq.thread.three.Demo5]-[DEBUG] 是否停止1?true 2018-12-07 [cn.qlq.thread.three.Demo5]-[DEBUG] 是否停止2?true 2018-12-07 [cn.qlq.thread.three.Demo5]-[DEBUG] end

3.能停止的线程 — 异常法

  在for循环种检测是否收到中断信号,收到中断信号就break。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.qlq.thread.three;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * for循环检测是否是停止状态,如果是停止状态就不执行后面代码
 * 
 * @author Administrator
 *
 */
public class Demo4 extends Thread {

    private static final Logger log = LoggerFactory.getLogger(Demo4.class);

    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 50; i++) {
            if (Thread.interrupted()) {
                log.debug("线程已经终止,我要退出");
                break;
            }
            log.debug("i={}", i);
        }
    }

    public static void main(String[] args) {
        try {
            Demo4 demo4 = new Demo4();
            demo4.start();
            Thread.sleep(3);
            // 发出中断信号
            demo4.interrupt();
        } catch (InterruptedException e) {
            log.error("InterruptedException ", e);
        }
        log.debug("end");
    }
}

结果:

2018-12-07 [cn.qlq.thread.three.Demo4]-[DEBUG] i=0 2018-12-07 [cn.qlq.thread.three.Demo4]-[DEBUG] i=1 2018-12-07 [cn.qlq.thread.three.Demo4]-[DEBUG] end 2018-12-07 [cn.qlq.thread.three.Demo4]-[DEBUG] 线程已经终止,我要退出

上面有个问题,如果for循环后面有语句还是会执行后面的语句,解决办法如下:(思路就是合理的利用异常机制)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.qlq.thread.three;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * for循环检测是否是停止状态,如果是停止状态就不执行后面代码
 * 
 * @author Administrator
 *
 */
public class Demo6 extends Thread {

    private static final Logger log = LoggerFactory.getLogger(Demo4.class);

    @Override
    public void run() {
        super.run();
        try {
            for (int i = 0; i < 50; i++) {
                if (Thread.interrupted()) {
                    log.debug("线程已经终止,我要退出");
                    // 抛出异常
                    throw new InterruptedException();
                }
                log.debug("i={}", i);
            }
            log.debug("for 后面的语句");
        } catch (InterruptedException e) {
            log.error("进入catch方法---", e);
        }
    }

    public static void main(String[] args) {
        try {
            Demo6 demo6 = new Demo6();
            demo6.start();
            Thread.sleep(3);
            // 发出中断信号
            demo6.interrupt();
        } catch (InterruptedException e) {
            log.error("InterruptedException ", e);
        }
        log.debug("end");
    }
}

结果:

2018-12-07 [cn.qlq.thread.three.Demo4]-[DEBUG] i=0 2018-12-07 [cn.qlq.thread.three.Demo4]-[DEBUG] end 2018-12-07 [cn.qlq.thread.three.Demo4]-[DEBUG] 线程已经终止,我要退出 2018-12-07 [cn.qlq.thread.three.Demo4]-[ERROR] 进入catch方法— java.lang.InterruptedException at cn.qlq.thread.three.Demo6.run(Demo6.java:24)

4.在沉睡种停止

如果线程在sleep中中断,会是什么效果?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.qlq.thread.three;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 沉睡中中断会进捕捉到中断异常
 * 
 * @author Administrator
 *
 */
public class Demo7 extends Thread {

    private static final Logger log = LoggerFactory.getLogger(Demo4.class);

    @Override
    public void run() {
        super.run();
        try {
            Thread.sleep(50 * 1000);
        } catch (InterruptedException e) {
            log.error("进入catch方法");
            log.info("demo7.isInterrupted  2-> {}", this.isInterrupted());
        }
    }

    public static void main(String[] args) {
        Demo7 demo7 = new Demo7();
        demo7.start();
        // 发出中断信号
        demo7.interrupt();
        log.info("demo7.isInterrupted  1-> {}", demo7.isInterrupted());
        log.debug("end");
    }
}

结果:

2018-12-07 [cn.qlq.thread.three.Demo4]-[ERROR] 进入catch方法 2018-12-07 [cn.qlq.thread.three.Demo4]-[INFO] demo7.isInterrupted 1-> true 2018-12-07 [cn.qlq.thread.three.Demo4]-[INFO] demo7.isInterrupted 2-> false 2018-12-07 [cn.qlq.thread.three.Demo4]-[DEBUG] end

可以看出线程在sleep状态下中断某一线程会进入catch语句,并且清除停止状态值,使之变为false。(这里也就解释了为什么sleep(long)抛出一个检查型异常(InterruptedException))。

上面代码是先中断后sleep,其实先interrupt后sleep也是一样的错误,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.qlq.thread.three;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 先中断后睡眠也会进入异常
 * 
 * @author Administrator
 *
 */
public class Demo8 extends Thread {

    private static final Logger log = LoggerFactory.getLogger(Demo4.class);

    public static void main(String[] args) {
        // 发出中断信号
        Thread.currentThread().interrupt();
        try {
            Thread.sleep(50000);
        } catch (InterruptedException e) {
            log.debug("interruptedException", e);
        }
    }
}

结果:

2018-12-07 [cn.qlq.thread.three.Demo4]-[DEBUG] interruptedException java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at cn.qlq.thread.three.Demo8.main(Demo8.java:20)

5.能停止的线程——stop 暴力停止(释放锁,容易造成数据不一致)

源码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Deprecated
    public final void stop() {
        stop(new ThreadDeath());
    }
    @Deprecated
    public final synchronized void stop(Throwable obj) {
        if (obj == null)
            throw new NullPointerException();

        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            checkAccess();
            if ((this != Thread.currentThread()) ||
                (!(obj instanceof ThreadDeath))) {
                security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
            }
        }
        // A zero status value corresponds to "NEW", it can't change to
        // not-NEW because we hold the lock.
        if (threadStatus != 0) {
            resume(); // Wake up thread if it was suspended; no-op otherwise
        }

        // The VM can handle all thread states
        stop0(obj);
    }
  private native void stop0(Object o);

  使用stop停止线程是非常暴力的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.qlq.thread.three;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * stop暴力停止
 * 
 * @author Administrator
 *
 */
public class Demo9 extends Thread {

    private static final Logger log = LoggerFactory.getLogger(Demo9.class);

    @Override
    public void run() {
        int i = 0;
        while (true) {
            log.debug("{}", i++);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Demo9 demo9 = new Demo9();
        demo9.start();
        Thread.sleep(100);
        // 暴力停止
        demo9.stop();
        log.debug("end");
    }
}

结果:

  可以看到直接杀死线程,解除由该线程获得的所有对象锁头,而且可能使对象处于不连贯状态,如果其他线程访问对象,而导致的错误很难检查。所以被废弃。

  调用stop()方法时会抛出java.lang.ThreadDeath,但是在通常情况下,此异常不需要显示的捕捉。(在JDK7中已经没有抛出异常了,查看上面源码也可以知道)

方法stop()已经作废,因为如果强制性让一个线程停止则有可能使一些清理性的工作得不到完成。另外的情况就是对锁定的对象进行了”解锁”,导致数据得不到同步的处理,出现数据不一致的情况。

  • 使用stop释放锁的不良后果:

  使用stop释放锁会造成数据不一致的情况。如果出现这样的情况,程序处理的数据就可能遭到破坏,最终导致程序执行的错误。

例如:(此处需要理解引用类型)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.qlq.thread.three;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * stop暴力停止释放锁造成的数据不一致
 * 
 * @author Administrator
 *
 */
public class Demo10 extends Thread {

    private static final Logger log = LoggerFactory.getLogger(Demo10.class);
    private SyncObj syncObj;

    public Demo10(SyncObj syncObj) {
        this.syncObj = syncObj;
    }

    @Override
    public void run() {
        syncObj.setValue("b", "bbb");
    }

    public static void main(String[] args) throws InterruptedException {
        SyncObj syncObj = new SyncObj();
        Demo10 demo9 = new Demo10(syncObj);
        demo9.start();
        Thread.sleep(5 * 1000);
        // 暴力停止
        demo9.stop();
        log.debug("syncObj - > {}", syncObj);
    }
}

class SyncObj {
    private String username = "a";
    private String password = "aaa";

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public synchronized void setValue(String username, String password) {
        try {
            this.username = username;
            // 休眠10秒中
            Thread.sleep(10 * 1000);
            this.password = password;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String toString() {
        return "SyncObj [username=" + username + ", password=" + password + "]";
    }
}

结果:(由于停止线程造成的数据不一致,只修改了username,没有修改密码)

2018-12-07 [cn.qlq.thread.three.Demo10]-[DEBUG] syncObj – > SyncObj [username=b, password=aaa]

6.使用return停止线程

  将interrupt与return结合也可以很好的实现停止线程的效果。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.qlq.thread.three;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * return + interrupt结束线程
 * 
 * @author Administrator
 *
 */
public class Demo11 extends Thread {

    private static final Logger log = LoggerFactory.getLogger(Demo11.class);

    @Override
    public void run() {
        while (true) {
            if (this.isInterrupted()) {
                log.debug("run收到终止信号,终止了!");
                return;
            }
            log.debug("sss");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        // 暴力停止
        Demo11 demo11 = new Demo11();
        demo11.start();
        Thread.sleep(100);
        demo11.interrupt();
    }
}

结果:

  建议使用抛异常的方法来实现线程的停止,因为在catch中还可以向上抛,使线程传播的事件得以传播。

2.暂停线程

  暂停线程意味着可以恢复运行。在Java多线程编程中,可以使用suspend()方法暂停线程,使用resume()恢复线程。这两个方法都是过期作废的方法。

源码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Deprecated
    public final void suspend() {
        checkAccess();
        suspend0();
    }

    @Deprecated
    public final void resume() {
        checkAccess();
        resume0();
    }

    private native void setPriority0(int newPriority);
    private native void stop0(Object o);
    private native void suspend0();
    private native void resume0();
    private native void interrupt0();
    private native void setNativeName(String name);

1.suspend()和resume()的使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.qlq.thread.three;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo12 extends Thread {

    private static final Logger log = LoggerFactory.getLogger(Demo12.class);
    private long i;

    @Override
    public void run() {
        while (true) {
            i++;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        // 暴力停止
        Demo12 demo12 = new Demo12();
        demo12.start();

        // A段
        Thread.sleep(500);
        demo12.suspend();
        log.debug("time1->{},i->{}", System.currentTimeMillis(), demo12.getI());
        Thread.sleep(500);
        log.debug("time2->{},i->{}", System.currentTimeMillis(), demo12.getI());

        // B段
        demo12.resume();
        Thread.sleep(500);

        // C段
        Thread.sleep(500);
        demo12.suspend();
        log.debug("time3->{},i->{}", System.currentTimeMillis(), demo12.getI());
        Thread.sleep(500);
        log.debug("time4->{},i->{}", System.currentTimeMillis(), demo12.getI());
    }

    public long getI() {
        return i;
    }

    public void setI(long i) {
        this.i = i;
    }
}

结果:

2018-12-07 [cn.qlq.thread.three.Demo12]-[DEBUG] time1->1544187679161,i->89828826 2018-12-07 [cn.qlq.thread.three.Demo12]-[DEBUG] time2->1544187679668,i->89828826 2018-12-07 [cn.qlq.thread.three.Demo12]-[DEBUG] time3->1544187680670,i->298679684 2018-12-07 [cn.qlq.thread.three.Demo12]-[DEBUG] time4->1544187681170,i->298679684

  从控制台打印的时间以及结果看,线程确实被暂停了,而且也可以恢复。

2.suspend()和resume()的缺点—独占(也就是suspend不会释放锁)

  在使用suspend()和resume()的时候极易造成公共的同步对象的独占,使其他线程无法访问公共同步对象。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.qlq.thread.three;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo13 extends Thread {

    private static final Logger log = LoggerFactory.getLogger(Demo13.class);
    private SyncObj2 syncObj2;

    public Demo13(String name, SyncObj2 syncObj2) {
        this.setName(name);
        this.syncObj2 = syncObj2;
    }

    @Override
    public void run() {
        syncObj2.testSync();
    }

    public static void main(String[] args) throws InterruptedException {
        SyncObj2 syncObj2 = new SyncObj2();
        Demo13 demo131 = new Demo13("a", syncObj2);
        demo131.start();
        // 休眠是为了使上面线程占用锁
        Thread.sleep(1000);

        Demo13 demo132 = new Demo13("b", syncObj2);
        demo132.start();

        // 打印状态
        System.out.println("demo131.getState()->" + demo131.getState());
        System.out.println("demo132.getState()->" + demo132.getState());
    }
}

class SyncObj2 {
    public synchronized void testSync() {
        System.out.println("进入testSync同步方法");
        if ("a".equals(Thread.currentThread().getName())) {
            System.out.println("此线程将挂起,永远不会释放锁,其他线程无法调用此方法");
            Thread.currentThread().suspend();
        }
        System.out.println("退出testSync同步方法");
    }
}

结果:(suspend之后线程处于可运行状态,等待锁的处于阻塞状态)

进入testSync同步方法 此线程将挂起,永远不会释放锁,其他线程无法调用此方法 demo131.getState()->RUNNABLE demo132.getState()->BLOCKED

jvisualvm查看线程状态:

另外一个需要注意的常见写法:(关于System.out.print()的同步)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.qlq.thread.three;

public class Demo14 extends Thread {

    int i;

    @Override
    public void run() {
        while (true) {
            System.out.println(i++);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Demo14 demo14 = new Demo14();
        demo14.start();

        Thread.sleep(100);
        demo14.suspend();
        System.out.println("main end");
    }
}

结果:(到最后都不会打印main end)

原因:println方法是一个同步方法,所以线程suspend之后没有释放锁,源码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public void println(String x) {
        synchronized (this) {
            print(x);
            newLine();
        }
    }

3.suspend()和resume()的缺点—不同步

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.qlq.thread.three;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * suspend和resume导致数据不同步
 * 
 * @author QiaoLiQiang
 * @time 2018年12月7日下午9:32:50
 */
public class Demo15 extends Thread {
    private static final Logger log = LoggerFactory.getLogger(Demo15.class);
    private SyncObj3 syncObj3;

    @Override
    public void run() {
        syncObj3.setVal("b", "bbb");// 启动线程设置值
    }

    public Demo15(String name, SyncObj3 syncObj3) {
        this.setName(name);
        this.syncObj3 = syncObj3;
    }

    public static void main(String[] args) throws InterruptedException {
        SyncObj3 syncObj3 = new SyncObj3();
        Demo15 demo15 = new Demo15("b", syncObj3);
        demo15.start();

        log.debug("main start");
        Thread.sleep(3 * 1000);
        demo15.suspend();// 暂停线程
        Thread.sleep(5 * 1000);
        log.debug("syncObj31->{}", syncObj3);

        demo15.resume();// 恢复线程
        Thread.sleep(1 * 1000);
        log.debug("syncObj32->{}", syncObj3);

        Thread.sleep(2000);
        log.debug("syncObj33->{}", syncObj3);
    }
}

class SyncObj3 {
    private String username = "a";
    private String password = "aaa";
    private static final Logger log = LoggerFactory.getLogger(SyncObj3.class);

    public void setVal(String username, String password) {
        this.username = username;

        try {
            log.debug("{}线程将要休眠5秒钟", Thread.currentThread().getName());
            Thread.sleep(5 * 1000);
            log.debug("{}线程睡醒了", Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug("{}线程设置密码的值,password->{}", Thread.currentThread().getName(), password);
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "SyncObj3 [username=" + username + ", password=" + password + "]";
    }
}

结果:

21:58:51 [cn.qlq.thread.three.Demo15]-[DEBUG] main start 21:58:51 [cn.qlq.thread.three.SyncObj3]-[DEBUG] b线程将要休眠5秒钟 21:58:59 [cn.qlq.thread.three.Demo15]-[DEBUG] syncObj31->SyncObj3 [username=b, password=aaa] 21:58:59 [cn.qlq.thread.three.SyncObj3]-[DEBUG] b线程睡醒了 21:58:59 [cn.qlq.thread.three.SyncObj3]-[DEBUG] b线程设置密码的值,password->bbb 21:59:00 [cn.qlq.thread.three.Demo15]-[DEBUG] syncObj32->SyncObj3 [username=b, password=bbb] 21:59:02 [cn.qlq.thread.three.Demo15]-[DEBUG] syncObj33->SyncObj3 [username=b, password=bbb]

  解释:main线程和b线程线程开始之后,主线程睡了3秒钟之后暂停了b线程,b线程此时也睡了3秒钟(还剩余睡眠2秒钟),暂停5秒钟之后恢复b线程,恢复之后就马上执行睡眠之后的代码(也就是暂停前的代码),所以没有继续睡眠之前剩余的两秒钟。总结起来:线程恢复之后会继续执行暂停时的代码,而且暂停过程中睡眠时间也在走(暂停不会导致睡眠时间的延迟)。

总结:

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

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

    上面两个方法都是过期作废的方法。

文中用到的相关知识点:引用传递、一个对象一把锁、synchronized方法实则是对当前对象加锁、synchronized同步代码块(关于同步会在下篇继续学习)。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/155117.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
前端实现markdown编辑器
在线测试地址: https://fangyuanxiaozhan.com/demo/md2html
zhaoolee
2018/12/24
1.9K0
前端实现markdown编辑器
小技巧,把Markdown文本发布到微信公众号文章
估计很多人都是这样,平常工作在github,等到有成果要发布,又要写微信公众号。 github用Markdown,微信公众号,至少截止今天,还是沿用富文本的方式。不是说富文本不好,但每次精心撰写的内容,重新排一遍版,还真是怪烦的。 如果在github是使用jekyll相对会容易一点,在页面上拷贝、到微信粘贴一下,大多内容都会差不多。否则就只好转换成html显示在浏览器,然后再拷贝粘贴。 Markdown转换成html大多人都会,有很多所见即所得的工具软件,比如Marked2,不过多数都是收费的。其
俺踏月色而来
2018/06/20
1.5K0
markdown样式代码保存
/*此样式是没任何效果的,留给你填写的 你可以随意修改,组合你想要的css样式 没有最好的,只有最合适的, 看看后面的示例,你就会懂得写个你最爱的样式,并保存了的! 建议先复制某一你喜欢的css模板样式到此样式下,再在此基础上自定义自己的css样式。 来试试吧! ^_^*/
xing.org1^
2020/02/14
7150
一份Markdown Here样式送给你
如果你还不知道什么是markdown,那么,推荐你去好好了解一下这个富文本语言,下一篇文章就是了。如果你还不知道什么时markdown here,推荐你去看这篇文章:
分享者
2022/05/17
3300
一份Markdown Here样式送给你
在WordPress中使用Markdown进行写作的正确姿势
在wordpress中使用markdown语法来进行写作,是很多wordpress博主都要想到的一点。虽然说现在wordpress已经“原生”支持wordpress语法,但是还是有很多的瑕疵,也并不实用,当然也有众多的markdown的插件:
老潘
2018/06/21
15.1K0
在WordPress中使用Markdown进行写作的正确姿势
利用css 设计markdown 主题
Markdown 入门 :文章目录生成、合并单元格、文章快速插入链接(使用剪切板的链接插到选中文字)【修订】
公众号iOS逆向
2021/07/29
5570
一套简约漂亮的响应式博客园主题皮肤分享给你们
  最近在自己博客园逛的时候,总会有一个感觉,真是太丑了,然而又觉得自己暂时抽不出太多的时间来搭建自己的博客系统,上网一搜才发现,原来我们可以自定义博客的布局以及样式的,那我就在网上找到了一个哥们的自定义Hexo经典主题Ligt的CSS文件,然后根据自己的审美及需要来做改动后上传以此来使自己的博客看起来像是自己搭建的个人博客。因为我总觉得一个良好的界面才会给博友读下去的欲望,否则很恶心,连自己都这么觉得。下面我们就来分享这个替换步骤教程。
阿豪聊干货
2018/08/09
2.2K0
一套简约漂亮的响应式博客园主题皮肤分享给你们
[Markdown]Sublime Text2配置成MarkdownPad2效果
原文链接:http://blog.csdn.net/humanking7/article/details/43516903
祥知道
2020/03/10
4230
两款非常漂亮的markdown格式css样式
如果你用了laravel 框架 你需要在 resources/views/vendor/mail/html/themes声明文件.css例如repayment.css
美团骑手
2021/01/18
9K0
SpringBoot技术栈搭建个人博客【前台开发/项目总结】Bootstrap or Vue?前台页面分析后台页面分析项目总结
前言:写前台真的是我不擅长的东西...所以学习和写了很久很久...前台页面大概开发了两天半就开发好了,采用的静态的html和bootstrap来写,写后台的时候纠结住了...怎么说呢,写页面真的是头疼... 前序文章链接:SpringBoot技术栈搭建个人博客【项目准备】:https://www.jianshu.com/p/0293368fe750 前序文章链接:SpringBoot技术栈搭建个人博客【后台开发】:https://www.jianshu.com/p/91c6c9fc67c4 Boo
我没有三颗心脏
2018/07/04
1.6K0
【拥抱鸿蒙】HarmonyOS实现扫码安装
一段时间以来,鸿蒙包安装仅依赖华为官方提供的工具链hdc,这需要鸿蒙设备借助数据线连接到能运行hdc命令的电脑,再使用命令行或者DevEco安装,安装过程过于繁琐,不方便内部测试。
郑知鱼
2025/05/23
2810
【拥抱鸿蒙】HarmonyOS实现扫码安装
SpringBoot技术栈搭建个人博客【前台开发/项目总结】
先吐槽一句..写页面是真的不擅长,然后限于时间的问题,我开始考虑换用Bootstrap来完成页面的编写,因为时间有限(我得在实习完之前把所有页面开发完),学习Vue对于我来说还是存在一些学习成本的,虽然之前已经通过文档博客之类的学得七七八八(emm..三三四四吧...)的样子,但我还是想尽可能的写好...还是用自己熟悉的Bootstrap来完成吧...
我没有三颗心脏
2018/06/30
9690
SpringBoot技术栈搭建个人博客【前台开发/项目总结】
如何编写神奇的「插件机制」,优化基于 Antd Table 封装表格的混乱代码 | 技术点评
.markdown-body{word-break:break-word;line-height:1.75;font-weight:400;font-size:15px;overflow-x:hidden;color:#333}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{line-height:1.5;margin-top:35px;margin-bottom:10px;padding-bottom:5px}.markdown-body h1{font-size:30px;margin-bottom:5px}.markdown-body h2{padding-bottom:12px;font-size:24px;border-bottom:1px solid #ececec}.markdown-body h3{font-size:18px;padding-bottom:0}.markdown-body h4{font-size:16px}.markdown-body h5{font-size:15px}.markdown-body h6{margin-top:5px}.markdown-body p{line-height:inherit;margin-top:22px;margin-bottom:22px}.markdown-body img{max-width:100%}.markdown-body hr{border:none;border-top:1px solid #ddd;margin-top:32px;margin-bottom:32px}.markdown-body code{word-break:break-word;border-radius:2px;overflow-x:auto;background-color:#fff5f5;color:#ff502c;font-size:.87em;padding:.065em .4em}.markdown-body code,.markdown-body pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace}.markdown-body pre{overflow:auto;position:relative;line-height:1.75}.markdown-body pre>code{font-size:12px;padding:15px 12px;margin:0;word-break:normal;display:block;overflow-x:auto;color:#333;background:#f8f8f8}.markdown-body a{text-decoration:none;color:#0269c8;border-bottom:1px solid #d1e9ff}.markdown-body a:active,.markdown-body a:hover{color:#275b8c}.markdown-body table{display:inline-block!important;font-size:12px;width:auto;max-width:100%;overflow:auto;border:1px solid #f6f6f6}.markdown-body thead{background:#f6f6f6;color:#000;text-align:left}.markdown-body tr:nth-child(2n){background-color:#fcfcfc}.markdown-body td,.markdown-body th{padding:12px 7px;line-height:24px}.markdown-body td{min-width:120px}.markdown-body blockquote{color:#666;padding:1px 23px;margin:22px 0;border-left:4px solid #cbcbcb;background-color:#f8f8f8}.markdown-body blockquote:after{display:block;content:""}.markdown-body blockquote>p{margin:10px 0}.markdown-body ol,.markdown-body ul{padding-left:28px}.markdown-body ol li,.markdown-body
ssh_晨曦时梦见兮
2021/03/05
5280
如何编写神奇的「插件机制」,优化基于 Antd Table 封装表格的混乱代码 | 技术点评
我的markdown样式
样式 * { font-family: "微软雅黑"; } html { padding: 0px; margin: 0px; color: #000; background: #fff; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } body{ padding: 0px 10px; margin: 0px; border: 1px dashed
码客说
2019/10/22
4800
基于Openresty搭建本地简易文档中心
OpenResty 是一个强大的 Web 应用服务器,Web 开发人员可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,更主要的是在性能方面,OpenResty可以 快速构造出足以胜任 10K 以上并发连接响应的超高性能 Web 应用系统。
品茗IT
2023/10/22
4040
基于Openresty搭建本地简易文档中心
CSS 基础代码库整理
由于考虑到重置样式会存在潜在的问题,例如我们在全局将strong变成了一个普通标记,在用户可编辑内容区域的strong就不会反应出效果来,用户就会产生很大的疑惑,为什么在编辑器中加粗了字体儿实际上显示出来的效果却没反应呢?
前端修罗场
2023/10/07
3000
PHPCMS更改后台编辑器样式
PHPCMS默认的后台样式用着不习惯,根前台的视觉差太大?没关系,改一下就是了。 后台编辑器样式文件 staticsjsckeditorcontents.css 把前台样式表中控制文字的那一部分拷贝进去稍微修改下即可,当然你可以自定义编辑器背景什么的,看个人喜好了。 我自己比较喜欢的样式现在分享给大家
李维亮
2021/07/09
1.7K0
mdnice序号自动排序之雁栖湖主题
这个主题之所以取名雁栖湖,是因为一篇文章:权威发布||2016年中国科学院大学大数据
灵魂画师牧码
2021/04/20
7550
mdnice序号自动排序之雁栖湖主题
【进阶之路】Mybatis-Plus中乐观锁@version注解的问题与解决方案
.markdown-body{word-break:break-word;line-height:1.75;font-weight:400;font-size:15px;overflow-x:hidden;color:#333}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{line-height:1.5;margin-top:35px;margin-bottom:10px;padding-bottom:5px}.markdown-body h1{font-size:30px;margin-bottom:5px}.markdown-body h2{padding-bottom:12px;font-size:24px;border-bottom:1px solid #ececec}.markdown-body h3{font-size:18px;padding-bottom:0}.markdown-body h4{font-size:16px}.markdown-body h5{font-size:15px}.markdown-body h6{margin-top:5px}.markdown-body p{line-height:inherit;margin-top:22px;margin-bottom:22px}.markdown-body img{max-width:100%}.markdown-body hr{border:none;border-top:1px solid #ddd;margin-top:32px;margin-bottom:32px}.markdown-body code{word-break:break-word;border-radius:2px;overflow-x:auto;background-color:#fff5f5;color:#ff502c;font-size:.87em;padding:.065em .4em}.markdown-body code,.markdown-body pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace}.markdown-body pre{overflow:auto;position:relative;line-height:1.75}.markdown-body pre>code{font-size:12px;padding:15px 12px;margin:0;word-break:normal;display:block;overflow-x:auto;color:#333;background:#f8f8f8}.markdown-body a{text-decoration:none;color:#0269c8;border-bottom:1px solid #d1e9ff}.markdown-body a:active,.markdown-body a:hover{color:#275b8c}.markdown-body table{display:inline-block!important;font-size:12px;width:auto;max-width:100%;overflow:auto;border:1px solid #f6f6f6}.markdown-body thead{background:#f6f6f6;color:#000;text-align:left}.markdown-body tr:nth-child(2n){background-color:#fcfcfc}.markdown-body td,.markdown-body th{padding:12px 7px;line-height:24px}.markdown-body td{min-width:120px}.markdown-body blockquote{color:#666;padding:1px 23px;margin:22px 0;border-left:4px solid #cbcbcb;background-color:#f8f8f8}.markdown-body blockquote:after{display:block;content:""}.markdown-body blockquote>p{margin:10px 0}.markdown-body ol,.markdown-body ul{padding-left:28px}.markdown-body ol li,.markdown-body
南橘
2021/04/02
4.1K0
【进阶之路】Mybatis-Plus中乐观锁@version注解的问题与解决方案
10个JS优化小技巧
.markdown-body{word-break:break-word;line-height:1.75;font-weight:400;font-size:15px;overflow-x:hidden;color:#333}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{line-height:1.5;margin-top:35px;margin-bottom:10px;padding-bottom:5px}.markdown-body h1{font-size:30px;margin-bottom:5px}.markdown-body h2{padding-bottom:12px;font-size:24px;border-bottom:1px solid #ececec}.markdown-body h3{font-size:18px;padding-bottom:0}.markdown-body h4{font-size:16px}.markdown-body h5{font-size:15px}.markdown-body h6{margin-top:5px}.markdown-body p{line-height:inherit;margin-top:22px;margin-bottom:22px}.markdown-body img{max-width:100%}.markdown-body hr{border:none;border-top:1px solid #ddd;margin-top:32px;margin-bottom:32px}.markdown-body code{word-break:break-word;border-radius:2px;overflow-x:auto;background-color:#fff5f5;color:#ff502c;font-size:.87em;padding:.065em .4em}.markdown-body code,.markdown-body pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace}.markdown-body pre{overflow:auto;position:relative;line-height:1.75}.markdown-body pre>code{font-size:12px;padding:15px 12px;margin:0;word-break:normal;display:block;overflow-x:auto;color:#333;background:#f8f8f8}.markdown-body a{text-decoration:none;color:#0269c8;border-bottom:1px solid #d1e9ff}.markdown-body a:active,.markdown-body a:hover{color:#275b8c}.markdown-body table{display:inline-block!important;font-size:12px;width:auto;max-width:100%;overflow:auto;border:1px solid #f6f6f6}.markdown-body thead{background:#f6f6f6;color:#000;text-align:left}.markdown-body tr:nth-child(2n){background-color:#fcfcfc}.markdown-body td,.markdown-body th{padding:12px 7px;line-height:24px}.markdown-body td{min-width:120px}.markdown-body blockquote{color:#666;padding:1px 23px;margin:22px 0;border-left:4px solid #cbcbcb;background-color:#f8f8f8}.markdown-body blockquote:after{display:block;content:""}.markdown-body blockquote>p{margin:10px 0}.markdown-body ol,.markdown-body ul{padding-left:28px}.markdown-body ol li,.markdown-body
Jimmy_is_jimmy
2021/02/05
5490
推荐阅读
相关推荐
前端实现markdown编辑器
更多 >
LV.2
专业逮虾户学生
目录
  • 1.停止线程
    • 1.停止不了的线程  
    • 2.判断线程是否终止
    • 3.能停止的线程 — 异常法
      • 4.在沉睡种停止
    • 5.能停止的线程——stop 暴力停止(释放锁,容易造成数据不一致)
    • 6.使用return停止线程
  • 2.暂停线程
    • 1.suspend()和resume()的使用
    • 2.suspend()和resume()的缺点—独占(也就是suspend不会释放锁)
    • 3.suspend()和resume()的缺点—不同步
    • 总结:
    •     suspend()方法可以暂停线程,而且不会释放同步锁,而且暂停不会导致睡眠时间的延长;
    •     resume()可以使线程恢复状态,而且会继续执行暂停前的剩余代码。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档