精华内容
下载资源
问答
  • 中断和线程的区别
    万次阅读
    2020-09-16 22:19:29

          线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。

    协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快

     

    从调度上看,goroutine的调度开销远远小于线程调度开销。

    OS的线程由OS内核调度,每隔几毫秒,一个硬件时钟中断发到CPU,CPU调用一个调度器内核函数。这个函数暂停当前正在运行的线程,把他的寄存器信息保存到内存中,查看线程列表并决定接下来运行哪一个线程,再从内存中恢复线程的注册表信息,最后继续执行选中的线程。这种线程切换需要一个完整的上下文切换:即保存一个线程的状态到内存,再恢复另外一个线程的状态,最后更新调度器的数据结构。某种意义上,这种操作还是很慢的。

    Go运行的时候包涵一个自己的调度器,这个调度器使用一个称为一个M:N调度技术,m个goroutine到n个os线程(可以用GOMAXPROCS来控制n的数量),Go的调度器不是由硬件时钟来定期触发的,而是由特定的go语言结构来触发的,他不需要切换到内核语境,所以调度一个goroutine比调度一个线程的成本低很多。

    从栈空间上,goroutine的栈空间更加动态灵活。

    每个OS的线程都有一个固定大小的栈内存,通常是2MB,栈内存用于保存在其他函数调用期间哪些正在执行或者临时暂停的函数的局部变量。这个固定的栈大小,如果对于goroutine来说,可能是一种巨大的浪费。作为对比goroutine在生命周期开始只有一个很小的栈,典型情况是2KB, 在go程序中,一次创建十万左右的goroutine也不罕见(2KB*100,000=200MB)。而且goroutine的栈不是固定大小,它可以按需增大和缩小,最大限制可以到1GB。

    goroutine没有一个特定的标识。

    在大部分支持多线程的操作系统和编程语言中,线程有一个独特的标识,通常是一个整数或者指针,这个特性可以让我们构建一个线程的局部存储,本质是一个全局的map,以线程的标识作为键,这样每个线程可以独立使用这个map存储和获取值,不受其他线程干扰。

    goroutine中没有可供程序员访问的标识,原因是一种纯函数的理念,不希望滥用线程局部存储导致一个不健康的超距作用,即函数的行为不仅取决于它的参数,还取决于运行它的线程标识

    更多相关内容
  • C++11关于thead的应用,利用std::condition std::mutex提供如何中断,停止继续功能,
  •   该方法“中断线程”,但仅仅是会设置该线程的中断状态位为true,至于中断的结果线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序本身。   线程会不时地检测这个中断标示位,以判断线程...
  • 线程中断 ... * 描述:标记法中断线程 */ public class ThreadDemo { private static class MyRunnable implements Runnable { public volatile boolean isQuit = false; @Override public void ru
  • interrupt字面上是中断的意思,但在Java里Thread.interrupt()方法实际上通过某种方式通知线程,并不会直接中止该线程
  • 线程的阻塞和中断

    千次阅读 2020-04-04 20:58:00
    阻塞非阻塞是形容多个线程之间的相互影响的,一个线程占用了临界区资源,那么其他线程必须在临界区外等待,阻塞是操作系统层面挂起,上下文切换了,所以性能不高。如果一个线程一直占用不释放资源,那么其他需要该...

    1 线程的阻塞

    阻塞和非阻塞是形容多个线程之间的相互影响的,一个线程占用了临界区资源,那么其他线程必须在临界区外等待,阻塞是操作系统层面挂起在内存,释放CPU,上下文切换了,所以性能不高。如果一个线程一直占用不释放资源,那么其他需要该临界区资源的线程都必须一直等待。非阻塞就是运行多个线程同时进入临界区,只要保证不把数据修改坏就行。

    • 阻塞情况分为三种:

      • 等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池(阻塞队列)中。其他线程唤醒它后进入锁池。
      • 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
      • 其他阻塞:运行的线程执行sleep()或join()方法时,或者发出I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时,join()等待线程终止或者超时,或者I/O处理完毕时,线程重新转入就绪状态。
    • 如果线程被阻塞,很有可能被永久阻塞,例如调用Object.wait()、ServerSocket.accept()和DatagramSocket.receive()时,都可能永久的阻塞线程。即使发生超时,在超时期满之前持续等待也是不可行和不适当的,所以,要使用某种机制使线程更早地退出阻塞状态

    2 中断

    2.1 Thread.interrupt()方法

    中断可以理解为线程的一个标志位属性,它表示一个线程是否被其他线程进行了中断操作。在java中,其他线程通过调用某线程的interrupt()方法对其进行中断操作,但只是改变了线程的中断状态,通知这个线程该中断了。至于这个中断状态改变后执行的操作,应该由被通知的线程自己处理。

    线程处于阻塞状态

    如果被中断线程处于阻塞状态(例如线程调用了Thread.sleep、thread.join、thread.wait、1.5中的condition.await、可中断的Channel上的 I/O 操作方法后可进入阻塞状态),则在线程在检查中断标示时如果发现中断标示为true,则会在这些阻塞方法调用处抛出InterruptedException异常。

    1. 对于wait()中等待notify/notifyAll唤醒的线程,正在某一对象的等待池中。这时如果它的中断状态被改变,那么它就会抛出InterruptedException异常。这个异常不是线程抛出的,而是wait方法,对象的wait方法内部会不断检查在此对象上等待的线程的状态,如果发现哪个线程的状态被置为已中断,则会抛出InterruptedException(同时清除中断标志位,设为false),意思就是这个线程不能再等待了,意义等同于唤醒它。

      与notify()的区别是,被notify/All唤醒的线程会继续执行wait下面的语句,而在wait中被中断的线程则将控制权交给了catch语句(catch中捕获InterruptedException异常),一些正常的逻辑要被放到catch中来运行。

    2. 对于sleep()中的线程,如果调用了Thread.sleep(1 year),现在后悔了,想让它早些醒过来,调用interrupt()方法就是唯一手段,只有改变它的中断状态,让它从sleep中将控制权转到处理异常的catch语句中,然后再由catch中的处理转换到正常的逻辑。同样,对于join中的线程也可以这样处理。

    3. I/O操作阻塞的线程,I/O操作可以阻塞线程一段相当长的时间,特别是牵扯到网络应用时。例如,服务器可能需要等待一个请求(request),又或者,一个网络应用程序可能要等待远端主机的响应。

      实现InterruptibleChannel接口的通道是可中断的,如果某个线程在可中断通道上因调用某个阻塞的 I/O 操作(常见的操作有:serverSocketChannel. accept()、socketChannel.connect、socketChannel.open、socketChannel.read、socketChannel.write、fileChannel.read、fileChannel.write)而进入阻塞状态,而另一个线程又调用了该阻塞线程的 interrupt 方法,这将导致该通道被关闭,并且已阻塞线程接将会收到ClosedByInterruptException,并且设置已阻塞线程的中断状态。另外,如果已设置某个线程的中断状态并且它在通道上调用某个阻塞的 I/O 操作,则该通道将关闭并且该线程立即接收到 ClosedByInterruptException,并仍然设置其中断状态。

    在Java程序中,最好的办法就是让线程从run()方法返回,可以设置共享变量做标志位,run时定期检查,但被阻塞时无法执行run方法,也就无法检查标志位。可以利用interrupt方法,在修改标志位之后调用interrupt方法,结束阻塞后再次运行run时检查标志位,则可以正常终止运行。

    • 如何处理InterruptedException:
      • 如果很清楚当前线程被中断后的处理方式,则在catch语句中按自己的方式处理。 通常是做好善后工作,主动退出线程。
      • 直接在方法声明中throws InterruptedException,丢给上层处理。这种方式也很常见,将中断的处置权交给具体的业务来处理
      • 重新设置中断标记位,Thread.currentThread().interrupt(),交给后续方法处理,
        原因是底层抛出InterruptedException时会清除中断标记位,捕获到异常后如果不想处理,可以重新设置中断标记位。
    正在运行的线程
    • Thread.interrupt()方法不会中断一个正在运行的线程。如果线程处于正常活动状态,interrupt()会将该线程中的中断标志设置为true,被设置中断标志的线程将继续正常执行,不受影响。
    其他线程
    • 还有一些阻塞方法不会响应interrupt,如等待进入synchronized段、Lock.lock()。他们不能被动的退出阻塞状态。

      synchronized在获锁的过程中是不能被中断的,意思是说如果产生了死锁,则不可能被中断。
      与synchronized功能相似的reentrantLock.lock()方法也是不可中断的,即如果发生死锁,那么reentrantLock.lock()方法无法终止,如果调用时被阻塞,则它一直阻塞到它获取到锁为止。但是如果调用带超时的tryLock方法reentrantLock.tryLock(long timeout, TimeUnit unit),那么如果线程在等待时被中断,将抛出一个InterruptedException异常,这是一个非常有用的特性,因为它允许程序打破死锁。也可以调用reentrantLock.lockInterruptibly()方法,相当于一个超时设为无限的tryLock方法。

    2.2 isInterrupted()/interrupted()
    • Thread.currentThread().isInterrupted():判断某个线程是否已被发送过中断请求。
    • Thread.interrupted():该方法调用后会将中断标示位清除,即重新设置为false。

    3 Thread.interrupt()源码分析

    4 小结

    终止一个Java线程最好的方式,就是让run()方法主动退出。因为强制的让一个线程被动的退出是很不安全的,内部的数据不一致会对程序造成不可预知的后果。
    为了能够通知一个线程需要被终止,Java提供了Thread.interrupt()方法,该方法会设置线程中断的标记位,并唤醒可中断的阻塞方法,包括Thread.sleep(),Object.wait(),nio通道的IO等待,以及LockSupport.park()。识别一个方法是否会被中断,只需要看其声明中是否会throws InterruptedException或ClosedByInterruptException。

    每个Java线程都会对应一个osthread,它持有了三种条件变量,分别用于Thread.sleep(),Object.wait()和unsafe.park()。Thread.interrupt()会依次唤醒三个条件变量,以达到中断的目的。线程的同步与唤醒最终都使用了pthread_cond_wait和pthread_cond_signal这些pthread库函数。

    【参考文档】
    阻塞(sleep等等)区别 中断(interrupt)+ 中断的意义
    Thread.interrupt()到底做了啥?
    线程中断详解

    展开全文
  • 内核线程、软中断和定时器有何区别? 在慢速中断的过程中,允许别的中断发生      Re: 内核线程、软中断和定时器有何区别? 2.4中还有慢速中断吗?  ...
    内核线程、软中断和定时器有何区别?

    在慢速中断的过程中,允许别的中断发生

     

     
     Re: 内核线程、软中断和定时器有何区别?

    2.4中还有慢速中断吗? 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    有,其实就是软中断. 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    你好快,就成newbie了,我努力了好几个月才成newbie 

    慢速中断不应该是软中断吧?如果说慢速中断是可以中断的中断,那应该是那种没有XX_INTERRUPT标志的中断,系统响应时会打开中断。 

    软中断应该就是tasklet 


     

     
     Re: 内核线程、软中断和定时器有何区别?

    我觉得首先讲一下LINUX的内核机制: 
    传统的UNIX把内核分成两部分:TOP HALF和BOTTOMHALF.BOTTOM呢是由异步事件来调用的,其实在LINUX中不严格的说就是中断.TOP是由系统调用来调用的.注意这里的 BOTTOM HALF和LINUX2.2中的并在LINUX2.4也支持的BH机制不是一回事情. 
    好了,现在讲你问的问题: 
    软中断其实就是把一个异步事件的响应分成两个部分的一个部分.另一个叫硬中断.硬中断必须实时响应,软中断可以等有时间再做,LINUX怎么调度软中断,有三个途径,从系统掉用,异常和中断中返回的时候有检查要不要执行软终端. 
    对于一个时钟,很显然时钟中断的服务程序也被分成两个部分,一个就是硬中断,一个就是软中断了.你说的定时器我估计就是指时钟中断的软中断. 
    对与内核线程,LINUX从2.4的一些高端版本好象也开始采用了对某些软中断使用这中方法,即把软中断作为一个线程来执行. 


     

     
     Re: 内核线程、软中断和定时器有何区别?

    从他的意思来看就是软中断. 
    我原来比NEWBIE的级别还高一点呢,现在我换名字了. 
    你说的TASKLET只是软中断的一种类型. 
    对于中断的服务程序的设计,要具体对待,对于服务程序不大,没有必要采用软中断机制.直接关中断就可以了.你说的对XXX_INTERUPT如果象你那么设计,就不是采用软中断的机制了,在早期的UNIX是这么实现的,即一个中断服务不分成两个部分,只是在服务程序中开哪些中断.譬如 XENIX2.3.4就是这么设计的.至于LINUX可以不可以也这么直接写服务程序,我不知道.不过通常都是软硬中断分开的. 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    我想你没有理解他的意思。他说的慢速中断是指没有SA_INTERRUPT标志的中断。 

    以下是相关代码: 
     

    int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action)
    
    {
    
    	int status;
    
    	int cpu = smp_processor_id();
    
    
    
    	irq_enter(cpu, irq);
    
    
    
    	status = 1;	/* Force the "do bottom halves" bit */
    
    
    
    
    	/*慢速中断则开中断*/
    
    	if (!(action->flags & SA_INTERRUPT))
    
    		__sti();
    
    
    	do {
    
    		status |= action->flags;
    
    		action->handler(irq, action->dev_id, regs);
    
    		action = action->next;
    
    	} while (action);
    
    	if (status & SA_SAMPLE_RANDOM)
    
    		add_interrupt_randomness(irq);
    
    	__cli();
    
    
    
    	irq_exit(cpu, irq);
    
    
    
    	return status;
    
    }
    
    
    
    


     
     
     Re: 内核线程、软中断和定时器有何区别?

    我觉得这个好象包括在软中断的机制里面吧? 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    你这里采用的就是软中断的机制之一的BH机制. 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    有没搞错?handle_IRQ_event()是IRQ!是硬中断! 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    wheelz说得对,我说的慢速中断就是慢速中断,不是软中断 
    软中断的处理函数是do_softirq(),在kernel/softirq.c文件中 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    >你这里采用的就是软中断的机制之一的BH机制. 

    这是硬中断,不是BH机制: 
    action->handler(irq, action->dev_id, regs); 
    BH机制的函数是无参数无返回的:) 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    你只知道其一,不知道其二,作为优化,软中断未必就必须那么执行,在没有其他硬中断的时候,就直接执行算了,你以为DO_IRQ里面的检查是做什么的呀?首先把ACTION=NULL的那一段的代码, 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    在执行硬中断的时候,如果没有检测到其他的高级中断,直接执行他的软中断算了.因此,从概念上说,他是属于软中断的,尽管他同硬中断一道执行的. 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    没有搞错,你假设一在他里面发生了高级的中断,他怎么处理?假设这个中断发生在其他的低级中断中,他怎么处理?还能执行到这个 IRQ_HANLDLER_EVENT么?不能,只能作为软中断执行了.这里做为优化,在没有检测到其他高级的中断的时候,直接就在硬中断后面把软中断执行掉了算了,从实际来讲,他是在硬中断之后执行的,但从概念上,他是属于软中断的范畴. 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    你仔细看一ULK2的4.6和4.7节,看看hande_IRQ_event 是不是书上所讲的deferrable function的涵义. 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    我都懒得跟你争,你居然认为handle_IRQ_event()是软中断? 


     

     
     Re: 内核线程、软中断和定时器有何区别?

    书上所讲的deferrable function指的是bottom half和tasklet,它们是由do_softirq调用的,而不是hande_IRQ_event. 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    好,既然有处理软中断的例程,那么我问:软中断在哪里产生的?也就是说,在什么地方,硬中断把软中断挂入队列?你只能在DO_IRQ中找. 
    从整个中断发生的流程来看,先是从IRQXXX_INTERUPT跳到COMMON_INTERUPPT,直到调用DO_IRQ,根据软中断的定义我们可以知道,他必须由硬中断产生,并挂入软中断处理队列,请问,这个处理动作在哪里产生的? 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    硬中断只产生中断请求队列,我确实不知道,硬中断还要处理中断请求.按照你的理解,第一个中断产生了一个handle_IRQ_event1中产生了一个中断2,它应该包含一个handle_IRQ_event2,只要没有被别的中断打断的话,就该执行完,那不就是event2在event1中执行了么? 你没有办法确定event2和event1是不是一个中断,假设是一个中断呢?你就必须考虑你的中断程序的可重入的问题.这无疑增加了驱动程序开发的难度. 
    另外,你说我错了没有什么关系,我错了,但是我可以说说我为什么有这么错误理解的理由,"懒得同我辩",搞得我好象是故意捣乱似的. 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    我想问题已经很清楚了,这只是一个概念上的问题,并没有谁对谁错,在争下去也没有什么意义,我觉得我或者freshground或者wheelz是不会被你说服的,你觉得你会被我们说服吗?:) 
    这里我们称呼你所说的软中断为慢速中断是因为 
    1.ldd2上是这么写的,我们也就这么称呼了 
    2.如果我们称慢速中断为软中断,那就会把开中断执行的硬中断(当然,你称它为软中断)和softirq搞混 

    希望大家不要为了一个概念的问题伤了和气,这好像太不值得了 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    呵呵,“懒得和你争”其实是我调侃的气话,我愿意向你道歉:-)。 

    下面我就你在两个讨论话题中的问题和你探讨。我觉得你对中断部分的理解是错误的, 
    具体说就是你没有仔细看do_IRQ() 


    >>硬中断只产生中断请求队列,我确实不知道,硬中断还要处理中断请求. 
    按照你的理解,第一个中断产生了一个handle_IRQ_event1中产生了一个中断2, 
    它应该包含一个handle_IRQ_event2,只要没有被别的中断打断的话,就该执行完, 
    那不就是event2在event1中执行了么? 你没有办法确定event2和event1是不是一个中断, 
    假设是一个中断呢?你就必须考虑你的中断程序的可重入的问题. 
    这无疑增加了驱动程序开发的难度. 


    没错,在这种情况下,event2是在event1中执行! 
    并且,event2和event1不可能是同一个中断, 
    do_IRQ()保证了这一点,因为,如果同一个中断第二次发生,其相应desc->status有 
    IRQ_INPROGRESS标志,这样局部变量action==NULL,不会得到赋值, 
    因此goto out;同时,desc->status会并上IRQ_PENDING标志,这样, 
    当上一次中断响应完成后(for循环中,handle_IRQ_event之后), 
    会检查IRQ_PENDING标志,因而再循环一次 
    再次处理本中断, 
    这样也解决了重入的问题。 



    >>我觉得从开中断哪里讨论是不合适的,而是从DO_IRQ这个涵数开始, 
    在该书的P215页的注释607-617行,这一段代码,一定要执行到么? 
    如果回答是否定的,即有可能执行到也有可能不执行到,而是延时执行, 
    那么延时到哪里执行?一个就是FOR循环,一个就DO_SOFTIRQ了, 
    用ULK2的话说就是DEFFERABLE FUNCTION了,从这个意义上讲, 
    不就是软中断了么? 


    这段代码是一定要执行的,只有在action==NULL的情况下才会goto out; 
    那么什么情况下action会等于NULL呢?只有IRQ_DISABLED和IRQ_INPROGRESS, 
    也就是说只有当前中断被禁止或正在处理的情况下该循环 
    才不会执行。 


    下面是do_IRQ()的代码,取自2.4.20 

     

    /*
    
     * do_IRQ handles all normal device IRQ's (the special
    
     * SMP cross-CPU interrupts have their own specific
    
     * handlers).
    
     */
    
    asmlinkage unsigned int do_IRQ(struct pt_regs regs)
    
    {	
    
    	/* 
    
    	 * We ack quickly, we don't want the irq controller
    
    	 * thinking we're snobs just because some other CPU has
    
    	 * disabled global interrupts (we have already done the
    
    	 * INT_ACK cycles, it's too late to try to pretend to the
    
    	 * controller that we aren't taking the interrupt).
    
    	 *
    
    	 * 0 return value means that this irq is already being
    
    	 * handled by some other CPU. (or is disabled)
    
    	 */
    
    	int irq = regs.orig_eax & 0xff; /* high bits used in ret_from_ code  */
    
    	int cpu = smp_processor_id();
    
    	irq_desc_t *desc = irq_desc + irq;
    
    	struct irqaction * action;
    
    	unsigned int status;
    
    #ifdef CONFIG_DEBUG_STACKOVERFLOW
    
    	long esp;
    
    
    
    	/* Debugging check for stack overflow: is there less than 1KB free? */
    
    	__asm__ __volatile__("andl %%esp,%0" : "=r" (esp) : "0" (8191));
    
    	if (unlikely(esp < (sizeof(struct task_struct) + 1024))) {
    
    		extern void show_stack(unsigned long *);
    
    
    
    		printk("do_IRQ: stack overflow: %ld\n",
    
    			esp - sizeof(struct task_struct));
    
    		__asm__ __volatile__("movl %%esp,%0" : "=r" (esp));
    
    		show_stack((void *)esp);
    
    	}
    
    #endif
    
    
    
    	kstat.irqs[cpu][irq]++;
    
    	spin_lock(&desc->lock);
    
    	desc->handler->ack(irq);
    
    	/*
    
    	   REPLAY is when Linux resends an IRQ that was dropped earlier
    
    	   WAITING is used by probe to mark irqs that are being tested
    
    	   */
    
    	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
    
    	status |= IRQ_PENDING; /* we _want_ to handle it */
    
    
    
    	/*
    
    	 * If the IRQ is disabled for whatever reason, we cannot
    
    	 * use the action we have.
    
    	 */
    
    	action = NULL;
    
    	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
    
    		action = desc->action;
    
    		status &= ~IRQ_PENDING; /* we commit to handling */
    
    		status |= IRQ_INPROGRESS; /* we are handling it */
    
    	}
    
    	desc->status = status;
    
    
    
    	/*
    
    	 * If there is no IRQ handler or it was disabled, exit early.
    
    	   Since we set PENDING, if another processor is handling
    
    	   a different instance of this same irq, the other processor
    
    	   will take care of it.
    
    	 */
    
    	if (!action)
    
    		goto out;
    
    
    
    	/*
    
    	 * Edge triggered interrupts need to remember
    
    	 * pending events.
    
    	 * This applies to any hw interrupts that allow a second
    
    	 * instance of the same irq to arrive while we are in do_IRQ
    
    	 * or in the handler. But the code here _disibledevent="darktable" valign="top" width="2%" rowspan="2">
    Re: 内核线程、软中断和定时器有何区别?

    "呵呵,“懒得和你争”其实是我调侃的气话,我愿意向你道歉:-)。" 
    嘻嘻,那么认真干嘛?我从来就喜欢胡思乱想,胡言乱语,只要你不生气就好了.这么郑重的
    道歉显得我太小气了哦. 

     

     
     Re: 内核线程、软中断和定时器有何区别?

    我觉得还是你们的有道理,在我仔细对照了ULK2和LDD2等资料之后,只是碰巧我找到了别人的学习笔记,理解的同我差不多,哈哈,也犯了和我一样的错误,转贴如下(太长了,只搞连接): 
    http://joyfire.net/jln/kernel/2.html#I367 

    展开全文
  • ​ 一个线程不应该由其他线程来强制中断或停止,而是应该有线程自己自行停止,自己来决定自己的命运。 ​ 所以,Thread.stop, Thead.suspend, Thead.resumer都已经被废弃了。​ 其次 ​ 在Java中没有办法立即停止一...

    中断机制

    什么是中断机制?

    首先
    ​ 一个线程不应该由其他线程来强制中断或停止,而是应该有线程自己自行停止,自己来决定自己的命运。
    ​ 所以,Thread.stop, Thead.suspend, Thead.resumer都已经被废弃了。

    其次
    ​ 在Java中没有办法立即停止一条线程,然而停止线程却显得尤为重要,如取消一个耗时操作。
    ​ 因此,Java提供了一种用于停止线程的协商机制–中断,即中断标识协商机制。

    中断只是一种协商协作机制,Java中没有给中断增加任何语法,中断的过程完全需要程序员自己实现。

    若要中断一个线程,你需要手动调用该线程的interrupt方法,该方法也仅仅是将线程对象的中断表示设置成true
    接着你需要自己写代码不断地检测当前线程的标识位,如果为true,表示别的线程请求这条线程中断

    每个线程对象中都有一个中断标识位,用于表示线程是否被中断;该标识位为true表示中断,为false表示未中断;
    通过调用线程对象的interrupt方法将该线程的标识为设为true; 可以在别的线程中调用,也可以在自己的线程中调用。

    在这里插入图片描述

    1. 通过volatile变量实现
    2. 通过AtomicBoolean实现
    3. 通过Thread类自带的中断api实例方法实现
     public static void main(String[] args)
        {
            Thread t1 = new Thread(() -> {
                while (true)
                {
                    if(Thread.currentThread().isInterrupted())
                    {
                        System.out.println(Thread.currentThread().getName()+"\t isInterrupted()被修改为true,程序停止");
                        break;
                    }
                    System.out.println("t1 -----hello interrupt api");
                }
            }, "t1");
            t1.start();
    
            System.out.println("-----t1的默认中断标志位:"+t1.isInterrupted());
    
            //暂停毫秒
            try { TimeUnit.MILLISECONDS.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); }
    
            //t2向t1发出协商,将t1的中断标志位设为true希望t1停下来
            new Thread(() -> {
                t1.interrupt();
            },"t2").start();
            //t1.interrupt();
    
        }
    
     static AtomicBoolean atomicBoolean = new AtomicBoolean(false);
        private static void m2_atomicBoolean()
        {
            new Thread(() -> {
                while (true)
                {
                    if(atomicBoolean.get())
                    {
                        System.out.println(Thread.currentThread().getName()+"\t atomicBoolean被修改为true,程序停止");
                        break;
                    }
                    System.out.println("t1 -----hello atomicBoolean");
                }
            },"t1").start();
    
            //暂停毫秒
            try { TimeUnit.MILLISECONDS.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); }
    
            new Thread(() -> {
                atomicBoolean.set(true);
            },"t2").start();
        }
    
    static volatile boolean isStop = false;
        private static void m1_volatile()
        {
            new Thread(() -> {
                while (true)
                {
                    if(isStop)
                    {
                        System.out.println(Thread.currentThread().getName()+"\t isStop被修改为true,程序停止");
                        break;
                    }
                    System.out.println("t1 -----hello volatile");
                }
            },"t1").start();
    
            //暂停毫秒
            try { TimeUnit.MILLISECONDS.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); }
    
            new Thread(() -> {
                isStop = true;
            },"t2").start();
        }
    

    总结:当对一个线程,调用interrupt方法时:
    ① 如果线程处于正常活动状态,那么会将该线程的中断标志设置为true, 仅此而已。
    被设置中断标志的线程将继续正常运行,不受影响
    所以,interrupt()并不能真正的中断线程,需要被调用的线程自己进行配合才行。

    ②如果线程处于阻塞状态(例如处理sleep、wait、join等状态),在别的线程中调用当前线程对象的interrupt方法,那么线程将立即退出被阻塞状态,并抛出一个interruptedException异常。

      public static void main(String[] args)
        {
            //实例方法interrupt()仅仅是设置线程的中断状态位设置为true,不会停止线程
            Thread t1 = new Thread(() -> {
                for (int i = 1; i <=300; i++)
                {
                    System.out.println("-----: "+i);
                }
                System.out.println("t1线程调用interrupt()后的的中断标识02:"+Thread.currentThread().isInterrupted());
            }, "t1");
            t1.start();
    
            System.out.println("t1线程默认的中断标识:"+t1.isInterrupted());//false
    
            //暂停毫秒
            try { TimeUnit.MILLISECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
            t1.interrupt();//true
            System.out.println("t1线程调用interrupt()后的的中断标识01:"+t1.isInterrupted());//true
    
            try { TimeUnit.MILLISECONDS.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println("t1线程调用interrupt()后的的中断标识03:"+t1.isInterrupted());
            //????---false中断不活动的线程不会产生任何影响。
            //ps: 两秒后线程已经执行完
        }
    

    中断协商案例深度解析

     public static void main(String[] args)
        {
            Thread t1 = new Thread(() -> {
                while (true)
                {
                    if(Thread.currentThread().isInterrupted())
                    {
                        System.out.println(Thread.currentThread().getName()+"\t " +
                                "中断标志位:"+Thread.currentThread().isInterrupted()+" 程序停止");
                        break;
                    }
    
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                       // Thread.currentThread().interrupt();//没有它,程序不会停止,为什么要在异常处,再调用一次??
                        e.printStackTrace();
                    }
    
                    System.out.println("-----hello InterruptDemo3");
                }
            }, "t1");
            t1.start();
    
            //暂停几秒钟线程
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
    
            new Thread(() -> t1.interrupt(),"t2").start();
        }
    
    /**
     * 1 中断标志位,默认false
     * 2 t2 ----> t1发出了中断协商,t2调用t1.interrupt(),中断标志位true
     * 3 中断标志位true,正常情况,程序停止,^_^
     * 4 中断标志位true,异常情况,InterruptedException,将会把中断状态将被清除,并且将收到InterruptedException 。中断标志位false
     *    导致无限循环
     *
     * 5 在catch块中,需要再次给中断标志位设置为true,2次调用停止程序才OK
     */
    

    官方描述

    在这里插入图片描述

    中断只是一种协商机制,修改中断标识位仅此而已,不是立刻stop打断

      public static void main(String[] args)
        {
            //测试当前线程是否被中断(检查中断标志),返回一个boolean并清除中断状态,
            // 第二次再调用时中断状态已经被清除,将返回一个false。
    
    
            System.out.println(Thread.currentThread().getName()+"\t"+Thread.interrupted()); //false
            System.out.println(Thread.currentThread().getName()+"\t"+Thread.interrupted());//false
            System.out.println("----1");
            Thread.currentThread().interrupt();// 中断标志位设置为true
            System.out.println("----2");
            System.out.println(Thread.currentThread().getName()+"\t"+Thread.interrupted());//true
            System.out.println(Thread.currentThread().getName()+"\t"+Thread.interrupted());//false
    
            LockSupport.park();
    
            Thread.interrupted();//静态方法
    
            Thread.currentThread().isInterrupted();//实例方法
        }
    

    静态方法interrupted将会清楚中断状态(源码传入的ClearInterrupted为true)

    实例方法isInterrupted则不会(传入的参数ClearInterrupted为false)

    总结

    线程中断相关的方法:

    public void interrupt(); interrupt()方法是一个实例方法
    它通知目标线程中断,也仅仅是设置目标线程的中断标志位为true.

    public boolean isInterrupted(); isInterrupted()方法也是一个实例方法
    它判断当前线程是否被中断(通过检查中断标志位)并获取中断标志

    public static boolean interrupted(), Thread类的静态方法interrupted()
    返回当前线程的中断状态真实值(boolean类型)后会将当前线程的中断状态设为false, 此方法调用之后会清除当前线程的中断标志位的状态(将中断标志位置为false了),返回当前值并清零置false

    线程等待和唤醒

    LockSupport是用来创建和其他同步类的基本线程阻塞原语

    文档

    在这里插入图片描述

    LockSupport中的 park()unpark() 的作用分别是阻塞线程和解除被阻塞的线程

    三种线程等待唤醒的方式

    1. 使用Object的wait()方法让线程等待,使用 Object中的notify()方法唤醒线程
    2. 使用JUC包中Condition的await方法让线程等待,使用signal()方法唤醒线程
    3. LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程

    Object

     private static void syncWaitNotify()
        {
            Object objectLock = new Object();
    
            new Thread(() -> {
                try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
                synchronized (objectLock){
                    System.out.println(Thread.currentThread().getName()+"\t ----come in");
                    try {
                        objectLock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"\t ----被唤醒");
                }
            },"t1").start();
    
            //暂停几秒钟线程
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
    
            new Thread(() -> {
                synchronized (objectLock){
                    objectLock.notify();
                    System.out.println(Thread.currentThread().getName()+"\t ----发出通知");
                }
            },"t2").start();
        }
    

    wait()和notify()必须放在同步代码块或同步方法中,并且成对出现
    必须现wait()在notify(),否则程序无法执行,无法唤醒


    Condition

     private static void lockAwaitSignal()
        {
            Lock lock = new ReentrantLock();
            Condition condition = lock.newCondition();
    
            new Thread(() -> {
                try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
                lock.lock();
                try
                {
                    System.out.println(Thread.currentThread().getName()+"\t ----come in");
                    condition.await();
                    System.out.println(Thread.currentThread().getName()+"\t ----被唤醒");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            },"t1").start();
    
            //暂停几秒钟线程
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
    
            new Thread(() -> {
                lock.lock();
                try
                {
                    condition.signal();
                    System.out.println(Thread.currentThread().getName()+"\t ----发出通知");
                }finally {
                    lock.unlock();
                }
            },"t2").start();
        }
    

    Condtion中的线程等待和唤醒方法,需要先获取锁
    一定要先await再signal


    LockSupport

    LockSupport类使用了一种名为Permit(许可)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可(permit)
    但与Semaphores不同,许可证不会累积,最多只有一个

    park()/park(Object blocker):阻塞,permit许可证默认没有不能方向,所以一开始调用park()方法当前线程就会阻塞,直到别的线程给当前线程发放permit,park方法才会被唤醒

    unpark(Thread thread):唤醒,调用unpark(thread)方法后,就会将thread线程的许可证permit发放,会自动唤醒park线程,即之前阻塞中的LockSupport.park()方法会立即返回

     public static void main(String[] args)
        {
            Thread t1 = new Thread(() -> {
                try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
                System.out.println(Thread.currentThread().getName() + "\t ----come in"+System.currentTimeMillis());
                LockSupport.park();
                System.out.println(Thread.currentThread().getName() + "\t ----被唤醒"+System.currentTimeMillis());
            }, "t1");
            t1.start();
    
            //暂停几秒钟线程
            //try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
    
            new Thread(() -> {
                LockSupport.unpark(t1);
                System.out.println(Thread.currentThread().getName()+"\t ----发出通知");
            },"t2").start();
    
        }
    

    LockSupport 天生无锁块要求
    之前错误的先唤醒后后等待,LockSupport照样支持,先unpark再park相当于提前有了通行证unpark,park时就没有拦截。park和unpark必须一一对应,因为许可证不会累积,最多只有一个

    总结

    LockSupport是一个线程阻塞工具类,所有的方法都是静态的,可以让线程在任意位置阻塞,阻塞之后也有对于的唤醒方法。归根结底,LockSupport调用的Unsafe中的native代码(native标识的方法即调用底层C++、C代码)。

    LockSupport提供的park() 和 unpark()方法实现阻塞线程和解除线程阻塞的过程
    LockSupport和每个使用它的线程都有一个许可(permit)关联。
    每个线程都有一个相关的permit,permit最多只有一个,重复调用unpark也不会累加凭证。

    理解

    线程阻塞需要消耗凭证(permit),这个凭证最多只有一个。

    当调用park方法时

    • 如果有凭证,则会直接消耗掉这个凭证然后正常退出;
    • 如果无凭证,就必须阻塞等待凭证可用;

    而unpark则相反,它会增加一个凭证,但凭证最多只能有一个,累加无效。

    为什么可以突破wait/notify的原有调用顺序?

    因为unpark获得了一个凭证,之后再调用park方法,就可以名正言顺的靠凭证消费,故不会阻塞。
    先发放了凭证后续可以畅通无阻。

    为什么唤醒两次后阻塞两次,但最终结果还是会阻塞线程?

    因为凭证的数量最多为1,连续调用两次unpark和调用一次unpark效果一样,只会增加一个凭证;
    而调用两次park却需要消费两个凭证,证不够不能放行。

    展开全文
  • 线程中断的几种方式

    千次阅读 2021-08-10 14:51:47
    3. 使用interrupt方法中断线程。 1.使用退出标识终止线程 当run方法执行完后,线程就会退出。但有时run方法是永远不会结束的。如在服务端程序中使用线程进行监听客户端请求,或是其他的需要循环处理的任务。在这种...
  • 硬件中断和软件中断区别

    千次阅读 2020-07-09 09:09:15
    1、硬件中断:指向量中断,即中断源的识别标志,可用来存放中断服务程序的入口地址或跳转到中断服务程序的入口地址。 2、软件中断:指软中断,是利用硬件中断的概念,用软件方式进行模拟,实现宏观上的异步执行效果...
  • JUC多线程线程中断停止

    千次阅读 2022-01-22 19:00:41
    如果不能很好地停止线程那么可能会导致各种问题,所以正确的停止线程是非常的重要的,常见的中断线程的方式有以下几种: ① 方式一:使用 Thread 类的 stop() 方法来终止线程; ② 方式二:根据 volatile 修饰的标志...
  • 线程中断详解

    万次阅读 多人点赞 2018-07-05 19:01:44
    中断线程线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序本身。线程会不时地检测这个中断标示...
  • 中断优先级和中断线程优先级

    千次阅读 2017-11-12 15:40:00
    中断是一种当今很重要的硬件与cpu通信的方式,主板上集成很多硬件,那么就可以认为会有很多中断,但是cpu的数目往往要少得多,那么肯定会有多个硬件中断竞争一个cpu的情况,任何系统(包括自然界)都不能乱套,肯定...
  • 多线程——2如何正确的中断线程

    千次阅读 2019-11-02 10:28:33
    线程探险——2常用方法 一、内容安排 什么是守护线程(Daemon Thread) Join方法的含义 自己join自己会是什么效果 Interrupt方法 综合案列:如何去停止线程 二、文章内容 1. 什么...
  • Java:线程的三种中断方式

    千次阅读 2021-05-27 10:40:16
    文章目录前言一、线程的Stop()操作二、线程的Interrupt()方法进行中断操作1.stop()方法的缺点2.Interrupt()方法三、使用run标志位进行判断总结 前言 在 Java 中,并发机制非常重要,但并不是所有程序语言...
  • 在本篇文章中我们给大家分享了关于Java线程中断的相关知识点内容以及相关代码实例,有兴趣的朋友们可以学习下。
  • 用于线程中断,该方法并不能直接中断线程,只会将线程的中断标志位改为true。它只会给线程发送一个中断状态,线程是否中断取决于线程内部对该中断信号做什么响应,若不处理该中断信号,线程就不会中断。 简而言之,...
  • 在我们的程序中经常会有一些不达到目的不会退出的线程,例如:我们有一个下载程序线程,该线程在没有下载成功之前是不会退出的,若此时用户觉得下载速度慢,不想下载了,这时就需要用到我们的线程中断机制了,告诉...
  • 进程和线程区别

    千次阅读 2019-04-12 16:30:58
    进程和线程区别在于,线程没有独立的存储空间,而是所属进程中的其他线程共享一个存储空间。 线程有4个状态:新建、就绪、运行、阻塞/睡眠/等待、死亡。 线程间的通信一般用wait()方.........
  • linux 中断线程

    千次阅读 2017-05-27 12:24:01
    为什么要进行中断线程化? 在 Linux 中,中断具有最高的优先级。不论在任何时刻,只要产生中断事件,内核将立即执行相应的中断处理程序,等到所有挂起的中断软中断处理完毕后才能执行正常的任务,因此有可能造成...
  • 线程中断到底是什么

    千次阅读 2020-03-27 09:28:41
    我们如何让线程安全的停止呢? 1. 线程自然终止 自然执行完或抛出未处理异常。 2. stop(),resume(),suspend()方法 stop(),resume(),suspend()已不建议使用,stop()会导致线程不会正确释放资源,suspend()容易导致...
  • 线程中断机制

    万次阅读 多人点赞 2017-08-18 12:02:55
    在 java中启动线程非常容易,大多数情况下是让一个线程执行完自己的任务然后自己停掉... 在当前的api中,Thread.suspend、Thread.stop等方法都被Deprecated了,线程只能用interrupt中断,而且不是立刻中断,只是发了一
  • 面试中的 进程和线程区别

    千次阅读 2017-09-04 11:46:08
    下面就叨唠叨唠面试中需要掌握的进程和线程区别。    进程 进程是对计算机的一种抽象; 1. 进程是一个计算过程,表示一个逻辑控制流,它造成一个假象,好像这个进程一直在独占CPU资源。 2. 进程拥有一个...
  • java线程中断(interrupt)

    千次阅读 2021-09-22 10:02:08
    一个线程在未正常结束之前, 被强制终止是很危险的事情. 因为它可能带来完全预料不到的严重后果比如会带着自己所持有的锁而永远的休眠,迟迟不归还锁等。...这里我们理解线程中断的使用场景使用时的注意事项,最后使
  • 线程响应中断

    千次阅读 2019-08-19 08:44:50
    首先介绍下Thread的两个方法: ...isInterrupted():检查线程中断标记 @Slf4j public class StopThread implements Runnable { public static void main(String[] args) throws InterruptedException { ...
  • 用户线程和内核线程区别

    千次阅读 2017-08-22 10:09:31
    内核级线程:切换由内核控制,当线程进行切换的时候,由用户态转化为内核态。切换完毕要从内核态返回用户态;可以很好的利用smp,即利用多核cpu。windows线程就是这样的。  2. 用户级线程内核的切换由用户态程序...
  • 最近在学习JUC框架的时候,发现了很多工具类都是支持可中断的,如AQS、FutureTask都是可以在线程执行中,支持对于中断的响应,所以需要对线程中断有个了解,才能更好的学习JUC的源码。 线程中断的作用: 线程中断...
  • 线程有四种状态:新建、就绪、阻塞死亡。 1)新建:当线程被创建时,它只会短暂地处于这种状态,在这段时间内,主要会执行一些初始化的的操作。 2)就绪:在这种状态下,只要调度器把时间片分配给线程,该线程就...
  • Linux - 线程 & 进程和线程区别

    千次阅读 2018-10-23 21:20:46
    线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。 一个线程可以创建撤销另一个线程;...
  • Qt 线程中断(终止,退出)

    千次阅读 2021-08-08 13:18:36
    场景: 有的时候我们开线程做耗时的任务, 但很久了也没有完成, 我可能会有会暂停线程(或者中止) Worker = make_shared<WorkerRandom>() Thread.start(); Worker->moveToThread(&Thread); connect...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 341,050
精华内容 136,420
关键字:

中断和线程的区别