精华内容
下载资源
问答
  • 这是本人开源的一套android单线程多任务断点下载的项目,可支持排队下载,我看网上很多人的下载任务都是只能更新当前界面,我就做了多界面刷新,调用简单只需3个步骤,1、注册下载监听。2、点击下载(自动判断状态)...
  • 单线程

    千次阅读 2020-03-21 21:31:25
    简单的说,单线程就是进程中只有一个线程。单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。以上是main方法,是一个主线程。多线程由一个或者多个线程组成的程序就是多...

    在这里插入图片描述
    简单的说,单线程就是进程中只有一个线程。单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。以上是main方法,是一个主线程。多线程由一个或者多个线程组成的程序就是多线程,Java中,一定是从主线程开始执行(main方法),然后在主线程的某个位置启动新的线程。二、线程的基本操作2.1 创建创建线程的两种方法1、继承java.lang.Thread上述代码中,MyThread类继承了类java.lang.Thread,并覆写了run方法。主线程从main方法开始执行,当主线程执行至t.start()时,启动新线程(注意此处是调用start方法,不是run方法),新线程会并发执行自身的run方法。2、实现java.lang.Runnable接口 Mythread通过实现Runnable接口,覆写了run方法,实现创建线程的过程,与继承Thread类创建的线程是一样的结果。实际Thread类里边也是通过实现Runnable接口,唯一不同的就是这里边的run方法是空的。里边具体的实现交由外层调用类采用override实现。注意事项:多线程的运行过程中,如果主线程已经执行完成,但是其子线程还在执行,那表明程序还未结束,等到所有的线程都执行完成时,程序才算结束。 2.2 暂停线程中的暂停操作是调用sleep实现的,此方法可以指定对应的时间,实现让线程暂停多久。值得注意的是 线程中如果持有锁,sleep结束之前锁会一直持有,到达时间后才会释放线程调用sleep方法可以实现暂停1s的输出效果,如果在线程执行过程中出现异常,当前线程就会被interrupt,此时异常InterrunpterException就会发生。2.3互斥Java中线程的共享互斥操作,会使用synchronized关键字。线程共享互斥的架构称为监视(monitor),而获取锁有时也称为“持有(own)监视”。每个锁在同一时刻,只能由一个线程持有。注意:synchronized方法或声明执行期间,如程序遇到任何异常或return,线程都会释放锁。1、synchronized方法Java示例1://synchronized实例方法public synchronized void deposit(int m) { System.out.print(“This is synchronized method.”);}注:synchronized实例方法采用this锁(即当前对象)去做线程的共享互斥。Java示例2://synchronized类方法public static synchronized void deposit(int m) { System.out.print(“This is synchronized static method.”);}注:synchronized类方法采用类对象锁(即当前类的类对象)去做线程的共享互斥。如上述示例中,采用类.class(继承自java.lang.Class)作为锁。2、synchronized声明Java示例:public void deposit(int m) { synchronized (this) { System.out.print(“This is synchronized statement with this lock.”); } synchronized (Something.class) { System.out.print(“This is synchronized statement with class lock.”); }}注:synchronized声明可以采用任意锁,上述示例中,分别采用了对象锁(this)和类锁(something.class)2.4 中断java.lang.Thread类有一个interrupt方法,该方法直接对线程调用。当被interrupt的线程正在sleep或wait时,会抛出InterruptedException异常。事实上,interrupt方法只是改变目标线程的中断状态(interrupt status),而那些会抛出InterruptedException异常的方法,如wait、sleep、join等,都是在方法内部不断地检查中断状态的值。interrupt方法Thread实例方法:必须由其它线程获取被调用线程的实例后,进行调用。实际上,只是改变了被调用线程的内部中断状态;Thread.interrupted方法Thread类方法:必须在当前执行线程内调用,该方法返回当前线程的内部中断状态,然后清除中断状态(置为false) ;isInterrupted方法Thread实例方法:用来检查指定线程的中断状态。当线程为中断状态时,会返回true;否则返回false。2.5 协调1、wait set / wait方法wait set是一个虚拟的概念,每个Java类的实例都有一个wait set,当对象执行wait方法时,当前线程就会暂停,并进入该对象的wait set。当发生以下事件时,线程才会退出wait set:①有其它线程以notify方法唤醒该线程②有其它线程以notifyAll方法唤醒该线程③有其它线程以interrupt方法唤醒该线程④wait方法已到期注:当前线程若要执行obj.wait(),则必须先获取该对象锁。当线程进入wait set后,就已经释放了该对象锁。下图中线程A先获得对象锁,然后调用wait()方法(此时线程B无法获取锁,只能等待)。当线程A调用完wait()方法进入wait set后会自动释放锁,线程B获得锁。2、notify方法notify方法相当于从wait set中从挑出一个线程并唤醒。下图中线程A在当前实例对象的wait set中等待,此时线程B必须拿到同一实例的对象锁,才能调用notify方法唤醒wait set中的任意一个线程。注:线程B调用notify方法后,并不会立即释放锁,会有一段时间差。3、notifyAll方法notifyAll方法相当于将wait set中的所有线程都唤醒。4、总结wait、notify、notifyAll这三个方法都是java.lang.Object类的方法(注意,不是Thread类的方法)。若线程没有拿到当前对象锁就直接调用对象的这些方法,都会抛出java.lang.IllegalMonitorStateException异常。obj.wait()是把当前线程放到obj的wait set;obj.notify()是从obj的wait set里唤醒1个线程;obj.notifyAll()是唤醒所有在obj的wait set里的线程。三、线程的状态转移当创建一个Thread子类或实现Runnable接口类的实例时,线程进入【初始】状态;调用实例的start方法后,线程进入【可执行】状态;系统会在某一时刻自动调度处于【可执行】状态的线程,被调度的线程会调用run方法,进入【执行中】状态;线程执行完run方法后,进入【结束】状态;处于【结束】状态的线程,在某一时刻,会被JVM垃圾回收;处于【执行中】状态的线程,若调用了Thread.yield方法,会回到【可执行】状态,等待再次被调度;处于【执行中】状态的线程,若调用了wait方法,会进入wait set并一直等待,直到被其它线程通过notify、notifyAll、interrupt方法唤醒;处于【执行中】状态的线程,若调用了Thread.sleep方法,会进入【Sleep】状态,无法继续向下执行。当sleep时间结束或被interrupt时,会回到【可执行状态】;处于

    U2FsdGVkX1+h9R8LqLB5sX3S6Gt3xaLtnXEwU1bWD2OGoCBFZVuPcFtKs4nxtL/9
    OBGnGdpbkHUepJfyzHOXU7jw+XDN6oAWqDMJ+QVODjZhBwvqvvwm0Jw/S4UHmRg0w3SZ7HYAcDSRtNxDK3jEVkhBTZlE0krSREFlPSlat3oXzxcrDiFxKNXdTLBeYeaVDIZQcOQQGk6BAzd3b4czmWVz72trurqZihnY0/o6B2hFrPhzNXjOcBrqPAx0Fomj3gtPCwXk4BNShI+kHNy9tl+CF99Ou/PKzofssSXv2r83XONxJsEDExOEhBucEgq6wpaQHAn1fOz8FgCzsgUJt7xDGRgLMEDhXIGfGkNt1eWdwKNktHAJ9ypREBVaXGEUcRmseqOFzNZgIQAt2hIx626sATVvBhIcNuQXrvVqbCtXgjr82MPF8yUFyrmuSmKWGc7iNyGJObg/tZ3P0oyGasB7NNl+LSqKWJk4ISFnPk2upwc/TPkpqs2wOyV4oX0DghKkxF8kJc8mOxLoJ3rGB0WIjIGhlDh4en1w6lcegvLJIWWm1gGyb4f+8JJpHhDVpOwSK9wuAmffcdTMsCkpWcT6htGy/ZskyI1GJD9o2fb9y+897WfJAtQYplCO4gJZX394WG4mjFaQEavY1jjilkvsEoxBqk8aoJhjhBdqnwrI3+Qgg3j1Kj3nX2mLA5YA0GiU2fbEK/PdL3cHRtDEudLUzbsO1/F7F5om1134O/OSvGQysnDWxiBwrrh4B53wHGztuh+LD91rGjq7YaDt8kfSWkV21Hi/csVeL2kDjl7i5++Hh5m/yACZDLa5Q0BcPZgGLC5fim+jZQlPv3y+ApeS4LkHhs5ryJ8SW/RCDFeS0+I3XUV/QrInSCWmg51k8dbO777KfKVEDiGfcwaBKJg4ttI2uHjHwyik43dvAKI9wyezWPLkyyra9BwiwZj9my9463nmvgU2bqlRiBajh4R9ezSvyG7YqDJ+lBKElkNDeTNZ+w73x7gRiKX+KSrq8s9bnpcn6xMnqVKU2bh+CJetHGdXcrcS5Ni2mRWfegDBJkt2NqpV+dsuOVwX4ttrxE/pwnsFdeaFLVAorX4mlkqzaMnaCn3riMjepraZ6pUFa38kupgAGTv14NbGU5saWqkBBVbPKaqXBkcNsdfsZTErmBHVmITP6sjDXmLGhjED9ruz32c5neVqTY2M5sOONXv05nozxUTmFt9949C9ojI72zh+23ZfaNmxRn96THUbCnRPl8scPpHGRYWOViN+EMyCtNcRYQNG/D7DdaqqcAkVa8zfY4pfYmSpdAsUtRkx5PpDch+ctJtQyV3GeNglNS45hBv2T+H+LE5H6D5nUYtWu8qNS5nAZTeAIFQDjfR8m4P8I6lIParVdovu0/P/audpClQ6xNrpx7Cf/3sfxsVrU6zJ1R47RrkYJa+2xq+QvuDKzK438uzAnYW03zXX9NQ10Fqf40WfGO/9Cw6WUY0XMJAoiZmJUJusBVZvHQDuEoanjHHsxb9cM4BpWRISgezxTB+Gv8KsYaIeEdHoEDPM7mrpvczyhv4/3JCOrpCQk3OE7G7Ow0r1W2IUnoWev1TUJShcnLtbOyv/SINJhSV6jdNmsj0oNESH6btvnrh/UBR0DDf/dBm+HvvFRPjt51Npy3rqFn5sT36wWc6D87CjNCCWJQ+Xwpn0uCyr8a7xuBIvFr1s1kLDLYglfJ/N+tPNR4T/N0M2wOYRyzUAeiws/Y45riXUFJH0BeBQGTCKTEU1f/YN7piDySyUJakDm+PkZUhbClSjFymtJ7b2+7NZVhMSV5cA6JSn1BBXfMkiFsyKxwEGleKkB4cYE4jdgan8EU8dk+iVfh5lMN2Fa1977mNZlV9gYqp290yWuLwiUoNfZn5yff0EjekI8wyZWY3hug44CSuiVqxpXm12YKM0Swljj5EXQM3rmEDY35tHfzFmuLieOVjkVGHS4fclsCJskuv2vE4L4bC8sIRbHWyBb1fQyKHhYAVzsqVl0absNwPCia2v892G66TMvXwsECLd4IiPd5jDfM812ruyZfw1Hhenk/PnKCYqo2ieCl7jn98nJH3l7hRHvTsdaaj16iE5P0i9A4QMEZrywmaYHuke+lgQyleG0GKNDO0T7O9H1UUDkQ29WD75b7UENEUH4FiI8DvkvCKBn+ECWhB/+UjX90rU5KcBOOs9TUHLMc8Ukcapo+Q0fLtCsObLc3mUh5UxGFIRPrsX67UfD3s68EZdmgYx+apnR1S4x3AZnS8GXSUhiwWVyzDxJjW50o27QL+HxvdV0lF1C8oiPGi1JGabG5oUrCGhdCvpY/Q4tI5djoRSrqcEcHLOmesjBNmbCZ1nqB+uvPsmgtpV3PkEDzBS7KbTJ3Nl5dbDKK5tkAPifx6w0NC9bP4j6NNKaYimLHM5rMaRoTtqqseQDRLUk+OwmS3/eu2w30tXyA7xg1IogB5gA3fpRyn0xX0FOPPKaIQl6bxzw8CYKwT7210/QVYFlit9dCNJ3Yl6TRa8gTCVpw74FPutKtOkkkIakdZaq1/b9VV8tyfBYpOvIhKXLsX+d04kp/st01/ZKI/bupSwXAb+wAp6t2v2Fy2OoGtwNYVED6TREa65w9a8hBrhZ/wasop9XRx+UYZqT6BMuZlZaTIwykvxAT7s6OKDyORPTytzODMyI9/QpPEElWq93fNJorgIs8VR1nuTgAbFzR553RHXks1WU7pATTLTI1x8rytIy9k7PG0XSTZO+DBDOm1G6tT4PGka+3Tz/UrgHtOBnPAND3vUttPubSbRo4CsVkTFZFOgXk4t64G4no5mi9cZg3lvZt+OegVYYslrNVAYpmOi0sK+Tz8v2bx4BCjikHqblU3jJzYt7Vbzie//zjynGyWgGgqrr1cZGWV8YmX4Bofr6gw2L2cd0tDKDqw2SUQP0A1pAlA+G/PhuyKM0FBG/fBoBYyIUdBq6J0X7w33dDxCitYDcNgVFaz9VETl2x6Ktcmgqo/g7o4b0FaFQcCO+sjP/5UBvpDTlC+oRnc3jYUDZmdUyoSl8weo17qvJ4y5zchxj0uTx1AkPnG2deOjWtn0Ze/25nFuZ5OSzDsjaFoqtoSXI6oYqKIXcXo4/u+6Wc20Dil4UNjkoG0Buwicc2enlpoft8nh4ynoUEXg32Q9Gsb+CslP1Mi0SwyMEzor7HoQ56yUgFOVEtSgFT9GTwjDIt6zFQwSf7xvE+DebZNCgn7fR1RXz3qtA/ce9u65y1peEa9x2VGn2kPWuQ/JBPwSgezOAKEy08tcoYziBcByueRnmsL4jqhXj9tsC0V0OhKZVAAk2KxerbhkdJnqlBotAZEfbDN7oDMuWp5DYazrFupN5clPGN1AUP55xEwnTkc2rxiD4pivHtW7GTP2HH2L33rfz7zO0PYyiYNV+2Do/L/W9+Y6ubOW6DVt5616t/l6o35pQ5eYVVjFByydn00QtX/RUXq8zPGIZP5U1i8ith0xGbQHglrJJnMhJo85zpwTl/btFZyLGJ44wRw8+dUkssu/z946CJ0fQG61jJuncVJ3z37cf143A0XK

    【执行中】状态的线程,若遇到阻塞I/O操作,也会停止等待I/O完成,然后回到【可执行状态】;<1>

    展开全文
  • 线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的, 即不同的线程可以执行同样的函数。 什么是多线程? 多线程是指程序中包含多个执行流,即在一个程序中可以同时...

    什么是进程?
    当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。
    而一个进程又是由多个线程所组成的。


    什么是线程?
    线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,
    即不同的线程可以执行同样的函数。


    什么是多线程?
    多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,
    也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。


    多线程的好处:
    可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,
    这样就大大提高了程序的效率。 


    多线程的不利方面:
    线程也是程序,所以线程需要占用内存,线程越多占用内存也越多; 
    多线程需要协调和管理,所以需要CPU时间跟踪线程; 
    线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;
    线程太多会导致控制太复杂,最终可能造成很多Bug;


    多线程与单线程的区别
    生活举例
    你早上上班,正要打卡的时候,手机响了。。你如果先接了电话,等接完了,在打卡,就是单线程。
    如果你一手接电话,一手打卡。就是多线程。
    2件事的结果是一样的。。你接了电话且打了卡。

     

    多线程处理的优点

    同步应用程序的开发比较容易,但由于需要在上一个任务完成后才能开始新的任务,所以其效率通常比多线程应用程序低。如果完成同步任务所用的时间比预计时间长,应用程序可能会不响应。多线程处理可以同时运行多个过程。例如,文字处理器应用程序在您处理文档的同时,可以检查拼写(作为单独的任务)。由于多线程应用程序将程序划分成独立的任务,因此可以在以下方面显著提高性能: 
    多线程技术使程序的响应速度更快,因为用户界面可以在进行其他工作的同时一直处于活动状态。 
    当前没有进行处理的任务可以将处理器时间让给其他任务。 
    占用大量处理时间的任务可以定期将处理器时间让给其他任务。 
    可以随时停止任务。 
    可以分别设置各个任务的优先级以优化性能。 

    是否需要创建多线程应用程序取决于多个因素。在以下情况下,最适合采用多线程处理:
    耗时或大量占用处理器的任务阻塞用户界面操作。 
    各个任务必须等待外部资源(如远程文件或 INTERNET 连接)。 

    例如,用于跟踪 WEB 页上的链接并下载满足特定条件的文件的 INTERNET 应用程序“ROBOT”。这种应用程序可以依次同步下载各个文件,也可以使用多线程同时下载多个文件。多线程方法比同步方法的效率高很多,因为即使在某些线程中远程 WEB 服务器的响应非常慢,也可以下载文件。

    下面是多线程的例子
    还在DOS时代,人们就在寻求一种多任务的实现。于是出现了TSR类型的后台驻留程序,比较有代表性的有SIDE KICK、VSAFE等优秀的TSR程序,这类程序的出现和应用确实给用户使用计算机带来了极大的方便,比如SIDE KICK,们编程可以在不用进编辑程序的状态下,一边编辑源程序,一边编译运行,非常方便。但是,DOS单任务操作系统的致命缺陷注定了在DOS下不可能开发出真正的多任务程序。进入WINDOWS3.1时代,这种情况依然没有根本的改变,一次应用只能做一件事。比如数据库查询,除非应用编得很好,在查询期间整个系统将不响应用户的输入。
     进入了WINDOWS NT和WINDOWS 9X时代,情况就有了彻底的改观,操作系统从真正意义上实现了多任务(严格地说,WIN9X还算不上)。一个应用程序,在需要的时候可以有许多个执行线程,每个线程就是一个小的执行程序,操作系统自动使各个线程共享CPU资源,确保任一线程都不能使系统死锁。这样,在编程的时候,可以把费时间的任务移到后台,在前台用另一个线程接受用户的输入。对那些对实时性要求比较高的编程任务,如网络客户服务、串行通信等应用时,多线程的实现无疑大大地增强了程序的可用性和稳固性。

    =====================================================================================

    坏处:增加了调度和管理的开销,带来了一些不确定性,需要复杂的同步机制,避免死锁等等。
    好处:一定程度上提高响应速度,在多核的情况下还是更能充分利用CPU资源的。

    =====================================================================================

    单线程的也就是程序执行时,所跑的程序路径(处理的东西)是连续顺序下来的,必须前面的处理好,后面的才会执行到。   
    (未细看)单线程和多线程的优缺点 - Daniel - 休子的博客       多线程嘛,举个例子也就是说程序可以同时执行2个以上相同类似的操作,比如一些搜索代理或者群发email的多线程软件,由于操作一次需要网络的返回信息   花的时间比较长,而对cpu来说却是空闲的,如果是一个一个顺序执行,那么搜索几千个IP就会花上好久好久。   而如果用多线程就可以在等待期间   加入其他的搜索,然后等待,这样可以提高效率。不过多线程和多进程公用一些资源时要考虑的问题好像也是一样的,对于一些公共资源或者公共变量的访问和修改时要注意特别的,需要一些锁定什么的,还有顺序问题的考虑。  
           多线程编程的目的,就是"最大限度地利用CPU资源",当某一线程的处理不需要占用CPU而只和I/O,OEMBIOS等资源打交道时,让需要占用CPU资源的其它线程有机会获得CPU资源。每个程序执行时都会产生一个进程,而每一个进程至少要有一个主线程。这个线程其实是进程执行的一条线索,除了主线程外你还可以给进程增加其它的线程,也即增加其它的执行线索,由此在某种程度上可以看成是给一个应用程序增加了多任务功能。当程序运行后,您可以根据各种条件挂起或运行这些线程,尤其在多CPU的环境中,这些线程是并发运行的。多线程就是在一个进程内有多个线程。从而使一个应用程序有了多任务的功能。多进程技术也可以实现这一点,但是创建进程的高消耗(每个进程都有独立的数据和代码空间),进程之间通信的不方便(消息机制),进程切换的时间太长,这些导致了多线程的提出,对于单CPU来说(没有开启超线程),在同一时间只能执行一个线程,所以如果想实现多任务,那么就只能每个进程或线程获得一个时间片,在某个时间片内,只能一个线程执行,然后按照某种策略换其他线程执行。由于时间片很短,这样给用户的感觉是同时有好多线程在执行。但是线程切换是有代价的,因此如果采用多进程,那么就需要将线程所隶属的该进程所需要的内存进行切换,这时间代价是很多的。而线程切换代价就很少,线程是可以共享内存的。所以采用多线程在切换上花费的比多进程少得多。但是,线程切换还是需要时间消耗的,所以采用一个拥有两个线程的进程执行所需要的时间比一个线程的进程执行两次所需要的时间要多一些。即采用多线程不会提高程序的执行速度,反而会降低速度,但是对于用户来说,可以减少用户的响应时间。上述结果只是针对单CPU,如果对于多CPU或者CPU采用超线程技术的话,采用多线程技术还是会提高程序的执行速度的。因为单线程只会映射到一个CPU上,而多线程会映射到多个CPU上,超线程技术本质是多线程硬件化,所以也会加快程序的执行速度。

    ====================================================================================

    如果线程出现死锁,唯一能证明的就是应用程序有问题,这并不是线程的缺点。

    线程相对于进程的优点:
    1、开销小
    2、资源共享性好。

    线程相对于进程的缺点:
    1、共享资源需要耗费一定的锁资源,同步相对复杂。
    2、一个线程崩溃可能导致整个进程崩溃,这个当然是自己的应用程序有问题

    ====================================================================================

    CPU是以时间片的方式为进程分配CUP处理时间的,当一个进程以同步的方式去完成几件事情时,此进程必须完成了第一件事情以后再做第二件事,如此按顺序地向CPU请求完成要做的事情。在此单线程的工作模式下,如果把CUP看作是一共有100个时间片的话,CPU可能一直都只是花了其中的10个时间片来处理当前进程所要做的事情,只是用到了CPU的10%的时间片,而其他时间都白白浪费了,当然,实际上CPU的工作模式还是做完一件事以后再去做另一件事,只是CUP的处理速度非常快,很快就处理完成所请求的情事。

        为了提高CPU的使用率,采用多线程的方式去同时完成几件事情而互不干扰,如当前进程要完成三件事情1、2、3,那么CPU会分别用10%的时间来同时处理这3件事情,从而让CPU的使用率达到了30%,大大地提高了CPU的利用率。多线程的好处在处理一些特殊的场合其优势尤其明显。比如下载文件,你要一边下载一边显示进度一边保存,在这种情况下,如果没有用多线程的话,没有意外的话一般都会把主线程阻塞,比如进度条的进度根本没有随着已下载的量而变化,堪至是整个窗体都动不了,用多线程就可以很好地解决这个问题。

        这里有一个生活实例可能更好地去理解多线程:回去看你女朋友做饭,正常的话她都会把洗好的菜(肉)先放到锅里煮,然后一边洗别的菜或处理别的事情,如:洗碗、收拾桌台准备开饭,人还是一个人,但她同时做几件事情,这样就可以大大地提高效率。总的一句话就是:CPU还是要花同样多的时间去完成所有的事情,但多线程可以让CPU掺插地同时做多件事情,在视觉上让用户觉得计算机在同时帮他处理多件事情,更好地改善用户体验。

         了解了多线程的好处以后,就要了解应该在什么样的情况下使用多线程技术。因为并不是说所有情况下用多线程都是好事,因为多线程的情况下,CPU还要花时间去维护,CPU处理各线程的请求时在线程间的切换也要花时间,所以一般情况下是可以不用多线程的,用了有时反而会得不偿失。大多情况下,要用到多线程的主要是需要处理大量的IO操作时或处理的情况需要花大量的时间等等,比如:读写文件、视频图像的采集、处理、显示、保存等。

     

    转载于:http://blog.csdn.net/u012134199/article/details/46290465

    展开全文
  • Redis单线程模型

    千次阅读 2019-09-18 21:58:16
    1.Redis单线程模型 1.1.文件事件处理器 1>.Redis基于Reactor模式开发了网络事件处理器,这个处理器就叫做文件事件处理器(file event handler).这个文件事件处理器是单线程的,所以Redis才叫做单线程的模型,文件事件...

    1.Redis单线程模型

    1.1.文件事件处理器

    1>.Redis基于Reactor模式开发了网络事件处理器,这个处理器就叫做文件事件处理器(file event handler).这个文件事件处理器是单线程的,所以Redis才叫做单线程的模型,文件事件处理器采用了IO多路复用机制同时监听多个socket,根据socket上的事件来选择对应的事件处理器来处理这个事件;

    2>.如果被监听的socket准备好执行accept,read,write,close等事件/操作的时候,跟事件/操作对应的文件事件就会产生,这个时候文件事件处理器就会调用之前关联好的事件处理器来处理这个事件;

    3>.文件事件处理器是单线程模式运行的,但是通过IO多路复用机制监听多个socket,可以实现高性能的网络通信模型.又可以跟内部其他单线程的模块进行对接,保证了Redis内部的线程模型的简单性;

    4>.文件事件处理器的结构包含4个部分

    ①.多个socket;

    ②.IO多路复用程序;

    ③.文件事件分派器;

    ④.事件处理器(命令请求处理器,命令回复处理器,连接应答处理器等等);

    5>.多个socket可能并发的产生不同的操作,每个操作对应不同的文件事件,但是IO多路复用程序会监听多个socket,会将socket放入一个队列中排队,然后每次从队列中取出一个socket给事件分派器,事件分派器再把socket分派给对应的事件处理器去处理;

    6>.当一个socket的事件被处理完之后,IO多路复用程序才会将队列中的下一个socket取出交给事件分派器.文件事件分派器再根据socket当前产生的事件来选择对应的事件处理器来处理;

    1.2.文件事件

    1>.当socket变得可读时(比如客户端对Redis执行write操作或者close操作),或者有新的可以应答的socket出现时(客户端对Redis执行connect操作),socket就会产生一个"AE_READABLE"事件;

    2>.当socket变得可写的时候(客户端对Redis执行read操作),socket就会产生一个"AE_WRITABLE"事件;

    3>.IO多路复用程序可以同时监听"AE_READABLE"和"AE_WRITABLE"两种事件,要是一个socket同时产生了"AE_READABLE"和"AE_WRITABLE"两种事件,那么文件事件分派器会优先处理"AE_READABLE"事件,然后才是"AE_WRITABLE"事件;

    1.3.常用的文件事件处理器

    1>.如果是客户端要连接Redis,那么会为socket关联连接应答处理器;

    2>.如果是客户端要写数据到Redis,那么会为socket关联命令请求处理器;

    3>.如果是客户端要从Redis中读取数据(Redis发送数据给客户端),那么会为socket关联命令回复处理器;

    1.4.客户端与Redis通信的一次流程

    如图:
    在这里插入图片描述
    说明:

    ①.在Redis启动及初始化的时候,Redis会(预先)将连接应答处理器跟"AE_READABLE"事件关联起来,接着如果一个客户端向Redis发起连接,此时就会产生一个"AE_READABLE"事件,然后由连接应答处理器来处理跟客户端建立连接,创建客户端对应的socket,同时将这个socket的"AE_READABLE"事件跟命令请求处理器关联起来;

    ②.当客户端向Redis发起请求的时候(不管是读请求还是写请求,都一样),首先就会在之前创建的客户端对应的socket上产生一个"AE_READABLE"事件,然后IO多路复用程序会监听到在之前创建的客户端对应的socket上产生了一个"AE_READABLE"事件,接着把这个socket放入一个队列中排队,然后由文件事件分派器从队列中获取socket交给对应的命令请求处理器来处理(因为之前在Redis启动并进行初始化的时候就已经预先将"AE_READABLE"事件跟命令请求处理器关联起来了).之后命令请求处理器就会从之前创建的客户端对应的socket中读取请求相关的数据,然后在自己的内存中进行执行和处理;

    ③.当客户端请求处理完成,Redis这边也准备好了给客户端的响应数据之后,就会(预先)将socket的"AE_WRITABLE"事件跟命令回复处理器关联起来,当客户端这边准备好读取响应数据时,就会在之前创建的客户端对应的socket上产生一个"AE_WRITABLE"事件,然后IO多路复用程序会监听到在之前创建的客户端对应的socket上产生了一个"AE_WRITABLE"事件,接着把这个socket放入一个队列中排队,然后由文件事件分派器从队列中获取socket交给对应的命令回复处理器来处理(因为之前在Redis这边准备好给客户端的响应数据之后就已经预先将"AE_WRITABLE"事件跟命令回复处理器关联起来了),之后命令回复处理器就会向之前创建的客户端对应的socket输出/写入准备好的响应数据,最终返回给客户端,供客户端来读取;

    ④.当命令回复处理器将准备好的响应数据写完之后,就会删除之前创建的客户端对应的socket上的"AE_WRITABLE"事件和命令回复处理器的关联关系;

    2.为什么Redis单线程模型也能效率这么高?

    1>.纯内存操作;

    2>.核心是基于非阻塞的IO多路复用机制;

    3>.底层使用C语言实现,一般来说,C 语言实现的程序"距离"操作系统更近,执行速度相对会更快;

    4>.单线程同时也避免了多线程的上下文频繁切换问题,预防了多线程可能产生的竞争问题;

    展开全文
  • Redis是目前广为人知的一个内存数据库,在各个场景中都有着非常丰富的应用,前段时间Redis推出了6.0的版本,在新版本中采用了多线程模型。 因为我们公司使用的内存数据库是自研的,按理说我对Redis的关注其实并不算...

    Redis是目前广为人知的一个内存数据库,在各个场景中都有着非常丰富的应用,前段时间Redis推出了6.0的版本,在新版本中采用了多线程模型。

    因为我们公司使用的内存数据库是自研的,按理说我对Redis的关注其实并不算多,但是因为Redis用的比较广泛,所以我需要了解一下这样方便我进行面试。

    总不能候选人用过Redis,但是我非要问人家阿里的Tair是怎么回事吧。

    所以,在Redis 6.0 推出之后,我想去了解下为什么采用多线程,现在采用的多线程和以前版本有什么区别?为什么这么晚才使用多线程?

    Redis不是已经采用了多路复用技术吗?不是号称很高的性能了吗?为啥还要采用多线程模型呢?

    本文就来分析下这些问题以及背后的思考。

    Redis为什么最开始被设计成单线程的?

    Redis作为一个成熟的分布式缓存框架,它由很多个模块组成,如网络请求模块、索引模块、存储模块、高可用集群支撑模块、数据操作模块等。

    很多人说Redis是单线程的,就认为Redis中所有模块的操作都是单线程的,其实这是不对的。

    我们所说的Redis单线程,指的是"其网络IO和键值对读写是由一个线程完成的",也就是说,Redis中只有网络请求模块和数据操作模块是单线程的。而其他的如持久化存储模块、集群支撑模块等是多线程的。

    所以说,Redis中并不是没有多线程模型的,早在Redis 4.0的时候就已经针对部分命令做了多线程化。

    那么,为什么网络操作模块和数据存储模块最初并没有使用多线程呢?

    这个问题的答案比较简单!因为:"没必要!"

    为什么没必要呢?我们先来说一下,什么情况下要使用多线程?

    多线程适用场景

    一个计算机程序在执行的过程中,主要需要进行两种操作分别是读写操作和计算操作。

    其中读写操作主要是涉及到的就是I/O操作,其中包括网络I/O和磁盘I/O。计算操作主要涉及到CPU。

    而多线程的目的,就是通过并发的方式来提升I/O的利用率和CPU的利用率。

    那么,Redis需不需要通过多线程的方式来提升提升I/O的利用率和CPU的利用率呢?

    首先,我们可以肯定的说,Redis不需要提升CPU利用率,因为Redis的操作基本都是基于内存的,CPU资源根本就不是Redis的性能瓶颈。

    所以,通过多线程技术来提升Redis的CPU利用率这一点是完全没必要的。

    那么,使用多线程技术来提升Redis的I/O利用率呢?是不是有必要呢?

    Redis确实是一个I/O操作密集的框架,他的数据操作过程中,会有大量的网络I/O和磁盘I/O的发生。要想提升Redis的性能,是一定要提升Redis的I/O利用率的,这一点毋庸置疑。

    但是,提升I/O利用率,并不是只有采用多线程技术这一条路可以走!

    多线程的弊端

    我们在很多文章中介绍过一些Java中的多线程技术,如内存模型、锁、CAS等,这些都是Java中提供的一些在多线程情况下保证线程安全的技术。

    线程安全:是编程中的术语,指某个函数、函数库在并发环境中被调用时,能够正确地处理多个线程之间的共享变量,使程序功能正确完成。

    和Java类似,所有支持多线程的编程语言或者框架,都不得不面对的一个问题,那就是如何解决多线程编程模式带来的共享资源的并发控制问题。

    虽然,采用多线程可以帮助我们提升CPU和I/O的利用率,但是多线程带来的并发问题也给这些语言和框架带来了更多的复杂性。而且,多线程模型中,多个线程的互相切换也会带来一定的性能开销。

    所以,在提升I/O利用率这个方面上,Redis并没有采用多线程技术,而是选择了多路复用 I/O技术。

    小结

    Redis并没有在网络请求模块和数据操作模块中使用多线程模型,主要是基于以下四个原因:

    • 1、Redis 操作基于内存,绝大多数操作的性能瓶颈不在 CPU
    • 2、使用单线程模型,可维护性更高,开发,调试和维护的成本更低
    • 3、单线程模型,避免了线程间切换带来的性能开销
    • 4、在单线程中使用多路复用 I/O技术也能提升Redis的I/O利用率

    还是要记住:Redis并不是完全单线程的,只是有关键的网络IO和键值对读写是由一个线程完成的。

    Redis的多路复用

    多路复用这个词,相信很多人都不陌生。我之前的很多文章中也够提到过这个词。

    其中在介绍Linux IO模型的时候我们提到过它、在介绍HTTP/2的原理的时候,我们也提到过他。

    那么,Redis的多路复用技术和我们之前介绍的又有什么区别呢?

    这里先讲讲Linux多路复用技术,就是多个进程的IO可以注册到同一个管道上,这个管道会统一和内核进行交互。当管道中的某一个请求需要的数据准备好之后,进程再把对应的数据拷贝到用户空间中。

    多看一遍上面这张图和上面那句话,后面可能还会用得到。

    也就是说,通过一个线程来处理多个IO流。

    IO多路复用在Linux下包括了三种,select、poll、epoll,抽象来看,他们功能是类似的,但具体细节各有不同。

    其实,Redis的IO多路复用程序的所有功能都是通过包装操作系统的IO多路复用函数库来实现的。每个IO多路复用函数库在Redis源码中都有对应的一个单独的文件。

    在Redis 中,每当一个套接字准备好执行连接应答、写入、读取、关闭等操作时,就会产生一个文件事件。因为一个服务器通常会连接多个套接字,所以多个文件事件有可能会并发地出现。

    一旦有请求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。

    所以,Redis选择使用多路复用IO技术来提升I/O利用率。

    而之所以Redis能够有这么高的性能,不仅仅和采用多路复用技术和单线程有关,此外还有以下几个原因:

    • 1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。

    • 2、数据结构简单,对数据操作也简单,如哈希表、跳表都有很高的性能。

    • 3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU

    • 4、使用多路I/O复用模型

    为什么Redis 6.0 引入多线程

    2020年5月份,Redis正式推出了6.0版本,这个版本中有很多重要的新特性,其中多线程特性引起了广泛关注。

    但是,需要提醒大家的是,Redis 6.0中的多线程,也只是针对处理网络请求过程采用了多线程,而数据的读写命令,仍然是单线程处理的。

    但是,不知道会不会有人有这样的疑问:

    Redis不是号称单线程也有很高的性能么?

    不是说多路复用技术已经大大的提升了IO利用率了么,为啥还需要多线程?

    主要是因为我们对Redis有着更高的要求。

    根据测算,Redis 将所有数据放在内存中,内存的响应时长大约为 100 纳秒,对于小数据包,Redis 服务器可以处理 80,000 到 100,000 QPS,这么高的对于 80% 的公司来说,单线程的 Redis 已经足够使用了。

    但随着越来越复杂的业务场景,有些公司动不动就上亿的交易量,因此需要更大的 QPS。

    为了提升QPS,很多公司的做法是部署Redis集群,并且尽可能提升Redis机器数。但是这种做法的资源消耗是巨大的。

    而经过分析,限制Redis的性能的主要瓶颈出现在网络IO的处理上,虽然之前采用了多路复用技术。但是我们前面也提到过,多路复用的IO模型本质上仍然是同步阻塞型IO模型

    下面是多路复用IO中select函数的处理过程:

    从上图我们可以看到,在多路复用的IO模型中,在处理网络请求时,调用 select (其他函数同理)的过程是阻塞的,也就是说这个过程会阻塞线程,如果并发量很高,此处可能会成为瓶颈。

    虽然现在很多服务器都是多个CPU核的,但是对于Redis来说,因为使用了单线程,在一次数据操作的过程中,有大量的CPU时间片是耗费在了网络IO的同步处理上的,并没有充分的发挥出多核的优势。

    如果能采用多线程,使得网络处理的请求并发进行,就可以大大的提升性能。多线程除了可以减少由于网络 I/O 等待造成的影响,还可以充分利用 CPU 的多核优势。

    所以,Redis 6.0采用多个IO线程来处理网络请求,网络请求的解析可以由其他线程完成,然后把解析后的请求交由主线程进行实际的内存读写。提升网络请求处理的并行度,进而提升整体性能。

    但是,Redis 的多 IO 线程只是用来处理网络请求的,对于读写命令,Redis 仍然使用单线程来处理。

    那么,在引入多线程之后,如何解决并发带来的线程安全问题呢?

    这就是为什么我们前面多次提到的"Redis 6.0的多线程只用来处理网络请求,而数据的读写还是单线程"的原因。

    Redis 6.0 只有在网络请求的接收和解析,以及请求后的数据通过网络返回给时,使用了多线程。而数据读写操作还是由单线程来完成的,所以,这样就不会出现并发问题了。

    参考资料:

    https://www.cnblogs.com/Zzbj/p/13531622.html https://xie.infoq.cn/article/b3816e9fe3ac77684b4f29348 https://jishuin.proginn.com/p/763bfbd2a1c2 《极客时间:Redis核心技术与实战》

    展开全文
  • 为什么说Redis是单线程的以及Redis为什么这么快!

    万次阅读 多人点赞 2018-03-07 17:39:56
    既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了(毕竟采用多线程会有很多麻烦!)。 可以参考: https://redis.io/topics/faq 看到这里,你可能会气哭!本以为会有什么重大的技术...
  • Java单线程与多线程

    千次阅读 2019-03-08 18:17:52
    在我们了解单线程和多线程之前,我们必须搞清楚什么是进程。 一个运行起来的程序就是一个进程! 那程序又是什么呢? 对程序的通俗定义就是:一段可执行的代码。 当我们执行一段Java程序时,就在java虚拟机(JVM)中...
  • Redis 单线程还是多线程?

    千次阅读 2019-09-18 09:51:27
    Redis 单线程还是多线程 前段时间无意间看到一篇博客,讲述了Redis6即将在年底发布的事情,好奇心驱动下搜索了官网,想看看新版Redis带来了什么新的功能,果然得到证实Redis在年底将发布新的版本:6.0,并且Redis...
  • 彻底理解js是单线程

    千次阅读 多人点赞 2020-04-29 13:28:37
    JS执行是单线程 单线程是指Js引擎执行Js时只分了一个线程给他执行,也就是执行js时是单线程的。 那么问题来了,什么是线程?进程又是什么? 在分析浏览器的渲染过程之前,我们先了解一下什么是进程和线程: (1)...
  • Redis是单线程还是多线程问题

    千次阅读 2020-08-08 11:52:47
    Redis是单线程还是多线程问题 在学习redis的过程中,很多文章都说redis是单线程,但在官方给出的说明中显示,redis6.0已经引入了多线程,对此我找了许多文档,将学习过程整理记录下来。 1、Redis单线程 在一开始的...
  • 单线程与多线程的区别

    万次阅读 多人点赞 2017-11-27 11:03:18
    什么是进程? 当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。...线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区
  • 单线程与多线程的区别?

    万次阅读 2018-08-29 16:58:35
    线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的, 即不同的线程可以执行同样的函数。 什么是多线程? 多线程是指程序中包含多个执行流,即在一个程序中可以同时...
  • SpringBoot使用@scheduled定时执行任务的时候是在一个单线程中,如果有多个任务,其中一个任务执行时间过长,则有可能会导致其他后续任务被阻塞直到该任务执行完成。也就是会造成一些任务无法定时执行的错觉。 可以...
  • 分别使用单线程和多线程把一个文件夹下的饿一百张图片复制到另一个文件夹下,比较它们的处理时间 使用单线程: package lesson19; import java.io.File; import java.io.FileInputStream; import java.io....
  • JavaScript单线程的运行机制

    千次阅读 2018-02-26 15:30:57
    每一种语言都有自己的运行机制,javascript当然也不例外,了解了js的运行机制,对于想要深入学习js的我们来说有着莫大的帮助... 单线程通俗的来说就是同一时间只能做一件事情,不能同时做几件事情,与传统的后台编程...
  • 多线程并发一定比单线程快吗?

    千次阅读 2019-08-02 19:19:54
    确实多线程在一定情况下比单线程更快。 下面的代码演示串行和并发执行并累加操作的时间,请分析:当count的数量增加 1万 -> 10万 -> 100万 -> 1000万 -> 1亿,下面的代码并发执行一定比串行执行快吗?...
  • Redis6.0之前是单线程模型 首先我们要明确一个共识,我们通常所说的Redis单线程是指获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理,这个主线程就是我们平时说的"单线程",而...
  • Ajax是单线程还是多线程

    千次阅读 2019-07-08 15:27:22
    首先明确一点:Ajax是单线程的,因为JavaScript是单线程的,Ajax属于JavaScript范畴,因此Ajax是单线程的。之所以我们可以利用Ajax做到多线程,这取决于Web服务器,服务端使用多线程处理请求。 然后再明确一点:...
  • 单线程单线程写一个变量是否需要加锁,刚毕业的时候我会有这样的想法:一个线程只读并没有改变变量的值并不会有两个线程同时写一个变量产生竞态,所以不用加锁,但是工作中长者给我指导都是多线程必须加锁,所以我...
  • 单线程一定是线程安全的吗

    千次阅读 2019-05-17 12:58:31
    单线程一定是线程安全的吗 单线程一定是线程安全的,因为我们常说的线程安全就是线程同步,也就是指多线程同时访问同一全局变量才会出现的问题,需要考虑线程同步。但是单线程不涉及到此类问题。 多线程的线程同步的...
  • Redis单线程与慢查询

    千次阅读 2019-02-26 13:19:31
    单线程 对于每个Redis实例,在内部是使用单线程来处理所有命令请求的,即所有命令在该线程中排队执行。同时需要注意的是单个Redis实例的16个数据库的操作也都是共享这个单线程的,所以在设计时,如果16个数据库或者...
  • 单线程和多线程的优缺点

    千次阅读 2018-08-23 12:58:55
    单线程和多线程的优缺点   单线程和多线程的优缺点 多线程处理的优点 同步应用程序的开发比较容易,但由于需要在上一个任务完成后才能开始新的任务,所以其效率通常比多线程应用程序低。如果完成同步任务所用的...
  • 可能对于redis的是单线程的都知道,但是如果被问到为什么是单线程?为什么单线程还那么快?可能会突然的一脸懵逼。本片博客主要整理一下这两个问题。 Redis问什么是单线程? redis官网有关于redis常见问题的回答...
  • 文章目录单 Reactor 单线程工作原理示意图方案说明方案优缺点分析优点缺点使用场景单 Reactor 多线程工作原理示意图方案说明方案优缺点分析优点缺点主从 Reactor 多线程工作原理示意图方案说明方案优缺点分析优点...
  • python的多线程与单线程的效率问题

    千次阅读 2018-11-01 15:54:29
    先了解下CPU的简单运行原理:  它运行速度非常快,1s内可以运行成千上万次,一个核心可以把1s切分成成千上万个时间... 再了解下单线程和多线程的区别:  先看下单进程,顾名思义,就是一条进程,类似于单向公路...
  • 1、首先redis是单线程的,为什么redis会是单线程的呢? 从redis的性能上进行考虑,单线程避免了上下文频繁切换问题,效率高; 从redis的内部结构原理进行考虑,redis是基于Reactor模式开发了自己的网络事件处理器:...
  • 浏览器多线程和js单线程

    万次阅读 2017-08-02 15:13:11
    0.前言开发过程中遇到js线程和ui渲染线程互斥问题。导致ui无法正常更新等问题。这些问题的根源就是因为浏览器的多线程和...1.知识点补充js单线程js运作在浏览器中,是单线程的,js代码始终在一个线程上执行,此线程被称
  • 问:多线程是不是能加快处理速度?...假设我要拷贝100万条数据,单CPU电脑,用一个进程,在单线程的情况下,CPU占用率为5%,耗时1000秒。那么当在这个进程下,开辟10个线程同时去运行,是不是CPU占用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,072,751
精华内容 429,100
关键字:

单线程