精华内容
下载资源
问答
  • 一、怎样唤醒一个阻塞线程? 如果线程是因为调用了wait()、sleep()或者join()方法而导致的阻塞,可以中断线程,并且通过抛出InterruptedException来唤醒它;如果线程是遇到了IO阻塞,无能为力,因为IO是操作系统...

    相信很多初学者与到这一问题时,都会比较懵,接下来,我以自己的理解做一总结,希望有所帮助。

    一、怎样唤醒一个阻塞的线程?

        如果线程是因为调用了wait()、sleep()或者join()方法而导致的阻塞,可以中断线程,并且通过抛出InterruptedException(修改了中断标记)来唤醒它;如果线程是遇到了IO阻塞,无能为力,因为IO是操作系统实现的,Java代码并没有办法直接接触到操作系统。(但答案太官方,笼统,InterruptedException第三部分会详细解释)

    二、详细的唤醒方法

    与InterruptedException并不冲突,只是针对不一样,InterruptedException是针对所有的

    1.sleep()方法

    sleep(毫秒),指定以毫秒为单位的时间,使线程在该时间内进入阻塞状态,期间得不到CPU的时间片,等到时间超时,会自动进入可执行状态。(进入休眠,但不会释放锁)

    2.suspend()和resume()方法(已弃用)

    已经被弃用

    挂起和唤醒线程,suspend e()使线程进入阻塞状态,只有对应的 resume e()被调用时,线程才会进入可执行状态。(已弃用,易发生死锁)

    3.yield()方法(不是阻塞方法)

    礼让,礼让不一定礼让,插队一定插入

    调用此方法,会使线程放弃当前分的CPU时间片,但此时线程仍然处于可执行状态,随时可以再次分得CPU时间片。yield()方法只能使同优先级的线程有执行的机会。调用yield()的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程。(暂停当前线程,礼让其他线程,且不一定成功)

    4.wait()和notify()方法

    两个方法配套使用,且必须配合Synchronized配合使用,wait()使得线程进入阻塞状态,它有两种形式,一种允许指定以毫秒为单位的一段时间作为参数,另一种没有参数。前者当notify()被调用或者超过指定时间时进入可执行状态,而后者则必须由对应的notify()调用。

    5.join()方法

    也叫线程加入或插队。是当前线程A调用另一个线程B的join()方法。当前线程A调用另一个线程的join()方法,当前线程A转入阻塞状态,直到线程B运行结束,线程A才由阻塞状态转为可执行状态。

    以上是Java线程唤醒和阻塞的五种常用方法,不同的方法有不同的特点,其中wait() 和 notify()是其中功能最强大、使用最灵活的方法,但这也导致了它们效率较低、较容易出错的特性

    三、线程中断与InterceptedException异常

    在了解InterceptException之前我们需要明确以下几个知识点,以及什么时候会抛出InterceptException异常。

    以上1,2(弃用),4,5均是阻塞方法

    当阻塞方法收到中断请求的时候就会抛出InterruptedException异常

       1.线程的五种状态

    1. 新建状态:新创建了一个线程对象
    2. 就绪状态:线程对象创建后,其他线程调用了该对象的start()方法,此时对象处于可运行状态。只等待获取CPU的使用权。即在就绪状态的进程除CPU之外,其他的运行所需资源都已全部获得。(万事具备,只欠CPU)
    3. 运行状态:就绪状态的线程获取了CPU,执行程序代码。
    4. 阻塞状态:阻塞状态时线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态
    5. 死亡状态:线程任务执行完毕或因异常退出了run()方法,该线程结束生命周期

    其中阻塞状态的情况分为三种:

    1. 等待阻塞:运行的线程执行wait()方法,该线程会释放占用的所有资源,包括锁。jvm会把该线程放入“等待池”中。进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒,
    2. 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则jvm会把该线程放入“锁池”中
    3. 其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,jvm会把该线程置为阻塞状态。当sleep()状态超时,或join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

       2.线程中断标记

    什么是线程中断?这个与linux中的命令 kill -9 pid并不同,并非中断后,就不可以运行了,中断可以理解为一种状态。比如我们使用杀毒软件时,突然不想杀毒了,点了暂停,这就是中断了一个线程

    关于中断状态,我们需要重点关注Thread类中的以下几个方法:

    - Thread.interrupt(),设置当前中断标记为true(类似属性的set方法)
    - Thread.isInterrupted(),检测当前的中断标记(类似属性的get方法)
    - Thread.interrupted(),检测当前的中断标记,然后重置中断标记为false(类似属性的get方法+set方法)
    因此interrupt中断机制并不是真正的将当前线程中断,而是一个中断标记的变化,线程可以自行调用相应方法检查中断标记的变化,但是他只是一个标志,如果线程本身不处理的话,那么程序还是会执行下去。就好比,老师在学校叮嘱要好好学习,具体什么时候,如何好好学习还是看自身。

    因此interrupt() 方法并不能立即中断线程,该方法仅仅告诉线程外部已经有中断请求,至于是否中断还取决于线程自己(即我们自己的处理逻辑)

    //Thread类中的实例方法,持有线程实例引用即可检测线程中断状态,类似于(属性的get方法)
    public boolean isInterrupted(){}
    
    //Thread中的静态方法 检测调用这个方法的线程是否已经中断
    //注意:这个方法返回中断状态的同时,会将此线程的中断状态重置为false
    //所以,如果我们联系调用两次这个方法的话。第二次的返回值肯定为true(类似于属性的get+set方法)
    public static boolean interrupted(){}
    
    // Thread 类中的实例方法,用于设置一个线程的中断状态为 true(类似于属性的set方法)
    public void interrupt() {}

    object类的wait

    Thread类的join(),sleep()

    这三个方法的相同之处是,方法上都有: throws InterruptedException

    如果线程阻塞在这些方法上(我们知道,这些方法会让当前线程阻塞),这个时候如果其他线程对这个线程进行了中断(修改中断标记),那么这个线程会从这些方法中立即返回,抛出 InterruptedException 异常(恰好被捕获),同时重置中断状态为 false(例子如中断异常的处理),接下来,看线程自身的处理。

    看下面这个例子

    public class InterruptTest {
       //这里用来打印消耗的时间
      private static long time = 0;
      private static void resetTime(){
        time = System.currentTimeMillis();
      }
      private static void printContent(String content){
        System.out.println(content + "     时间:" + (System.currentTimeMillis() - time));
      }
    
      public static void main(String[] args) {
    
        test1();
    
      }
    
      private static void test1(){
    
        Thread1 thread1 = new Thread1();
        thread1.start();
    
        //延时3秒后interrupt中断
        try {
          Thread.sleep(3000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
    
        //将thread1的中断标记设为true
        thread1.interrupt();  
        printContent("执行中断");
    
      }
    
      private static class Thread1 extends Thread{
    
        @Override 
        public void run() {
          resetTime();
          int num = 0;
          while (true){
            if(isInterrupted()){
              printContent("当前线程 isInterrupted");
              break;
            }
    
            num++;
    
            if(num % 100 == 0){
              printContent("num : " + num);
            }
          }
        }
      }
    }

    执行结果如下:

    分析:main线程睡眠3秒,thread1开始执行,当main线程修改thread1的中断表之后,isInterrupted()判断为true,线程终止,也就是说interrupt和isInterrupted在这里起到的作用就相当于setXX和getXX的作用,维护着一个boolean变量。如果我们把判断逻辑去掉,那么线程仍然会继续执行,这也就说明了中断标记只是一个布尔标志,是否停止,还是还是要靠线程自身

    3.中断异常处理

    当然interrupt机制并不仅仅是一个中断状态位的变化和检测,它还可以进行中断异常的处理。我们知道Thread.sleep()方法需要捕获中断异常,那接下来我们往其中添加一个sleep延时试试

      while (true){
        if(isInterrupted()){
          printContent("当前线程 isInterrupted");
          break;
        }
    
        num++;
    
        //thread1  sleep一下
        try {
          Thread.sleep(1);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
    
        if(num % 100 == 0){
          printContent("num : " + num);
        }
      }

    执行结果如下

    你会发现,出现了异常,又继续执行了。这说明了什么问题?

    说明其他线程(main线程)在中断thread1线程后,thread1立即停止了,但又抛出了InterruptedException异常。

    恰好此时sleep这个阻塞方法强制要求捕获这个异常,捕获后,将中断标志又改为了false,这也是为什么异常被捕获,程序继续执行,且isInterrupted为false。

    展开全文
  • java唤醒一个阻塞线程

    千次阅读 2018-04-02 15:39:13
    如果线程是因为调用了wait()、sleep()或者join()方法而导致的阻塞,可以中断线程,并且通过抛出InterruptedException来唤醒它;如果线程遇到了IO阻塞,无能为力,因为IO是操作系统实现的,Java代码并没有办法直接...

    如果线程是因为调用了wait()sleep()或者join()方法而导致的阻塞,可以中断线程,并且通过抛出InterruptedException来唤醒它;如果线程遇到了IO阻塞,无能为力,因为IO是操作系统实现的,Java代码并没有办法直接接触到操作系统。以下是详细的唤醒方法:

    1. sleep() 方法

    sleep(毫秒),指定以毫秒为单位的时间,使线程在该时间内进入线程阻塞状态,期间得不到cpu的时间片,等到时间过去了,线程重新进入可执行状态。(暂停线程,不会释放锁)

    2.suspend() resume() 方法

    挂起和唤醒线程,suspend e()使线程进入阻塞状态,只有对应的resume e()被调用的时候,线程才会进入可执行状态。(不建议用,容易发生死锁)

    3. yield() 方法

    会使的线程放弃当前分得的cpu时间片,但此时线程任然处于可执行状态,随时可以再次分得cpu时间片。yield()方法只能使同优先级的线程有执行的机会。调用 yield()的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程。(暂停当前正在执行的线程,并执行其他线程,且让出的时间不可知)

    4.wait() notify() 方法

    两个方法搭配使用,wait()使线程进入阻塞状态,调用notify()时,线程进入可执行状态。wait()内可加或不加参数,加参数时是以毫秒为单位,当到了指定时间或调用notify()方法时,进入可执行状态。(属于Object类,而不属于Thread类,wait()会先释放锁住的对象,然后再执行等待的动作。由于wait()所等待的对象必须先锁住,因此,它只能用在同步化程序段或者同步化方法内,否则,会抛出异常IllegalMonitorStateException.

    5.join()方法

    也叫线程加入。是当前线程A调用另一个线程Bjoin()方法,当前线程转A入阻塞状态,直到线程B运行结束,线程A才由阻塞状态转为可执行状态。

    以上是Java线程唤醒和阻塞的五种常用方法,不同的方法有不同的特点,其中wait() notify()是其中功能最强大、使用最灵活的方法,但这也导致了它们效率较低、较容易出错的特性,因此,在实际应用中应灵活运用各种方法,以达到期望的目的与效果!


    转载于:https://blog.51cto.com/12306609/2093835

    展开全文
  • Thread类提供了一个holdsLock(Object obj)方法,当且仅当对象obj的监视器被某条线程持有的时候才会返回true,注意这是一个static方法,这意味着”某条线程”指的是当前线程。 ...

    Thread类提供了一个holdsLock(Object obj)方法,当且仅当对象obj的监视器被某条线程持有的时候才会返回true,注意这是一个static方法,这意味着”某条线程”指的是当前线程。

    如果线程是因为调用了wait()、sleep()或者join()方法而导致的阻塞,可以中断线程,并且通过抛出InterruptedException来唤醒它;如果线程遇到了IO阻塞,无能为力,因为IO是操作系统实现的,Java代码并没有办法直接接触到操作系统。

    多线程的上下文切换是指CPU控制权由一个已经正在运行的线程切换到另外一个就绪并等待获取CPU执行权的线程的过程。

    展开全文
  • 如何在一个线程中指定休眠或唤醒一个线程背景及问题:在线一个聊天的程序,客户端有两个线程:A和B。服务器发送一个消息到客户端,这两个线程都有接收的功能,想让A接收消息而阻塞B不让他接收。办法:1. 线程B用来...

    如何在一个线程中指定休眠或唤醒另一个线程


    背景及问题:


    在线一个聊天的程序,客户端有两个线程:A和B。服务器发送一个消息到客户端,这两个线程都有接收的功能,想让A接收消息而阻塞B不让他接收。


    办法:


    1. 线程B用来做什么的?两个线程都有接收功能,又要A优先于B,那么就要确保A先接收,B在A接收的情况下才接收?
    如果是,就让B来判断A的接收状态就可以了。


    2. 可以设计一个公共接收接口,A/B线程均可调用。然后在函数体内部添加判断:当前运行线程是指定线程(这里是A线程)的时候才接收。片段:


    //假定其他地方已经启动了线程A 和B
    pthread_t pid_a;
    pthread_t pid_b;

    int custom_recv(...)
    {
          //判断当前线程是否是A 线程
          pthread_t current_thread = pthread_self();

          //非A 线程,稍作休眠,退出
          if(!pthread_equal(current_thread,pid_a))
          {
              sleep(1);
              return 0;
          }
          //A线程,继续接收
         .............
    }

    转载于:https://blog.51cto.com/a4412/1422693

    展开全文
  • 在Java发展史上曾经使用suspend()、resume()方法对于线程进行阻塞唤醒,但随之出现很多问题,比较典型的还是死锁问题。 解决方案可以使用以对象为目标的阻塞,即利用Object类的wait()和notify()方法实现线程阻塞。...
  • 在socket 通讯时候,程序退出时候,socket并未释放,这就导致socket线程阻塞了 1、同步阻塞: 等待锁的释放 ... 3、使用thread.join 造成的阻塞,等待上一个线程进入RUNNABLE状态 4、使用threa...
  • 如何唤醒或者退出被阻塞,休眠的线程,非TerminateXXX方法
  • java 多线程 同步阻塞 唤醒
  • 线程之Java线程阻塞唤醒

    万次阅读 2014-12-06 18:58:01
    线程阻塞唤醒在多线程并发过程中是一个关键点,当线程数量达到很大的数量级时,并发可能带来很多隐蔽的问题。如何正确暂停一个线程,暂停后又如何在一个要求的时间点恢复,这些都需要仔细考虑的细节。在Java发展...
  • Java线程唤醒阻塞

    千次阅读 2016-10-09 09:37:18
    阻塞指的是暂停一个线程的执行以等待某个条件发生(如某资源就绪),学过操作系统的同学对它一 定已经很熟悉了。Java 提供了大量方法来支持阻塞,下面让我们逐一分析。 转载于:...
  • UDP的多线程程序,一般开一个线程循环调用recvfrom接收消息,当程序中止的时候,如果这个线程阻塞在recvfrom调用,并且没有消息到达,则这个线程无法终止,造成资源泄露等问题。 这里终止这个线程有六种方法: 1. ...
  • 线程阻塞唤醒

    千次阅读 2017-07-17 16:44:20
    线程阻塞唤醒的方法如图: package newThread;import java.util.Scanner;public class Twothread implements Runnable { private int i; @Override public void run() { //run方法同样是线程执行体 for(;i...
  • Java线程阻塞唤醒

    2018-05-07 00:35:38
    Thread.suspend和Thread.resume因为容易导致死锁,很早以前就被标记为@deprecated,不建议使用了。我们把线程使用互斥锁访问的共享资源叫做...如果使用resume方法唤醒线程前需要获取监视器,那么死锁就会发生。当然...
  • 本文主要向大家分享了Java多线程中的阻塞唤醒的相关内容,通过这篇文章大家可以大致了解到进入线程阻塞状态和可执行状态的方法,需要的朋友可以了解下。
  • 如果线程是因为调用了wait()、sleep()或者join()方法而导致的阻塞,可以中断线程,并且通过抛出InterruptedException来唤醒它;如果线程遇到了IO阻塞,无能为力,因为IO是操作系统实现的,Java代码并没有办法直接...
  • 如果线程是因为调用了wait()、sleep()或者join()方法而导致的阻塞,可以中断线程,并且通过抛出InterruptedException来唤醒它;如果线程遇到了IO阻塞,无能为力,因为IO是操作系统实现的,Java代码并没有办法直接...
  • 线程阻塞唤醒在多线程并发过程中是一个关键点,当线程数量达到很大的数量级时,并发可能带来很多隐蔽的问题。如何正确暂停一个线程,暂停后又如何在一个要求的时间点恢复,这些都需要仔细考虑的细节。Java为我们...
  • 什么是LockSupport LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。 该类与使用它的每个线程关联一个...LockSupport类使用了一种名为permit(许可)的概念来做到阻塞唤醒线程的功能,每个线程都有一个
  • 线程阻塞唤醒

    2019-09-14 08:58:36
    Java的线程阻塞唤醒是通过Unsafe类的park和unpark方法做到的。 两方法都是native方法,本身由c实现的核心功能。 park:是让当前运行的线程Thread.currentThread()休眠。 unpark:是唤醒指定线程。 两方法...
  • 目录 1.LockSupport功能简介 1.1 使用wait,notify阻塞唤醒线程 1.2 使用LockSupport阻塞唤醒线程 2. LockSupport的其他特色 2.1 可以先唤醒线程阻塞线程 2.2 先唤醒线程两次再阻...
  • 1. 现有一个主线程和子线程A,在主线程中调用SuspengThread()使得A被挂起; 2. 主线程中调用ResumeThread()使得A恢复运行; 3. 主线程立刻调用SuspendThread()意图挂起A时,主线程竟然被阻塞在了调用处!也就是说...
  • java线程阻塞唤醒的四种方式

    万次阅读 2018-03-07 17:49:05
    java在多线程情况下,经常会使用到线程阻塞唤醒,这里就为大家简单介绍一下以下几种阻塞/唤醒方式与区别,不做详细的介绍与代码分析 suspend与resume Java废弃 suspend() 去挂起线程的原因,是因为 suspend...
  • 从JDK源码角度看线程阻塞唤醒

    千次阅读 2016-05-21 08:39:41
    其中suspend与resume因为存在无法解决的竟态问题而被Java废弃,同样,wait与notify也存在竟态条件,wait必须在notify之前执行,假如一个线程先执行notify再执行wait将可能导致一个线程永远阻塞,如此一来,必须要...
  • 线程阻塞唤醒在多线程并发过程中是一个关键点,当线程数量达到很大的数量级时,并发可能带来很多隐蔽的问题。如何正确暂停一个线程,暂停后又如何在一个要求的时间点恢复,这些都需要仔细考虑的细节。Java为我们...
  • 唤醒一个运行线程 } 子线程实现如下: void subThreadProcess(void) { while { do something } } 在主线程中只能访问到子线程的接口subThreadProcess,无法知道其内部实现。 ...
  • put:向队列中存入一个元素,如果已满,则阻塞当前线程,等待唤醒。如果正常存入了元素,那么唤醒其他阻塞线程(有些执行take操作的线程因为队列为空而阻塞) take:从队列中取一个元素,如果队列为空,则阻塞当前...
  • 实时接收发送消息(接收消息线程阻塞,发送消息线程唤醒),
  • 如果线程是因为调用了wait()、sleep()或者join()方法而导致的阻塞,可以中断线程,并且通过抛出InterruptedException来唤醒它;如果线程遇到了IO阻塞,无能为力,因为IO是操作系统实现的,Java代码并没有办法直接...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 130,460
精华内容 52,184
关键字:

怎么唤醒一个阻塞的线程