精华内容
下载资源
问答
  • 为什么要用多线程

    千次阅读 热门讨论 2018-01-16 15:01:43
    以前我认为多线程的作用就是提升性能。实际上,多线程并不一定能提升性能(甚至还会降低性能);多线程也不只是为了提升性能。多线程主要有以下的应用场景:  1、避免阻塞(异步调用)  单个线程中的程序,...
    以前我认为多线程的作用就是提升性能。实际上,多线程并不一定能提升性能(甚至还会降低性能);多线程也不只是为了提升性能。多线程主要有以下的应用场景: 

    1、避免阻塞(异步调用) 

    单个线程中的程序,是顺序执行的。如果前面的操作发生了阻塞,那么就会影响到后面的操作。这时候可以采用多线程,我感觉就等于是异步调用。这样的例子有很多: 

    ajax调用,就是浏览器会启一个新的线程,不阻塞当前页面的正常操作; 

    流程在某个环节调用web service,如果是同步调用,则需要等待web service调用结果,可以启动新线程来调用,不影响主流程; 

    android里,不要在ui thread里执行耗时操作,否则容易引发ANR; 

    创建工单时,需要级联往其他表中插入数据,可以将级联插入的动作放到新线程中,先返回工单创建的结果…… 

    2、避免CPU空转 

    以http server为例,如果只用单线程响应HTTP请求,即处理完一条请求,再处理下一条请求的话,CPU会存在大量的闲置时间 

    因为处理一条请求,经常涉及到RPC、数据库访问、磁盘IO等操作,这些操作的速度比CPU慢很多,而在等待这些响应的时候,CPU却不能去处理新的请求,因此http server的性能就很差 

    所以很多web容器,都采用对每个请求创建新线程来响应的方式实现,这样在等待请求A的IO操作的等待时间里,就可以去继续处理请求B,对并发的响应性就好了很多 

    当然,这种设计方式并不是绝对的,现在像node.js、Nginx等新一代http server,采用了事件驱动的实现方式,用单线程来响应多个请求也是没问题的。甚至实现了更高的性能,因为多线程是一把双刃剑,在提升了响应性的同时,创建销毁线程都是需要开销的,另外CPU在线程之间切换,也会带来额外的开销。避免了这些额外开销,可能是node.js等http server性能优秀的原因之一吧 

    3、提升性能 

    在满足条件的前提下,多线程确实能提升性能 

    打一个比方,多线程就相当于,把要炒的菜放到了不同的锅里,然后用不同的炉来炒,当然速度会比较快。本来需要先炒西红柿,10分钟;再炒白菜10分钟;加起来就需要20分钟。用了多线程以后,分别放在2个锅里炒,10分钟就都炒好了 

    基本上,需要满足3个条件: 

    第1,任务具有并发性,也就是可以拆分成多个子任务。并不是什么任务都能拆分的,条件还比较苛刻 

    子任务之间不能有先后顺序的依赖,必须是允许并行的 

    比如 
    Java代码  收藏代码
    1. a = b + c  
    2. d = e + f  

    这个是可以并行的; 
    Java代码  收藏代码
    1. a = b + c  
    2. d = a + e  

    这个就无法并行了,第2步计算需要依赖第1步的计算结果,即使分成2个线程,也不会带来任何性能提升 

    另外,还不能有资源竞争。比如2个线程都需要写一个文件,第1个线程将文件锁定了,第2个线程只能等着,这样的2个子任务,也不具备并发性;执行sychronized代码,也是同样的情况 

    第2,只有在CPU是性能瓶颈的情况下,多线程才能实现提升性能的目的。比如一段程序,瓶颈在于IO操作,那么把这个程序拆分到2个线程中执行,也是无法提升性能的 

    第3,有点像废话,就是需要有多核CPU才行。否则的话,虽然拆分成了多个可并行的子任务,但是没有足够的CPU,还是只有一个CPU在多个线程中切换来切换去,不但达不到提升性能的效果,反而由于增加了额外的开销,而降低了性能。类似于虽然把菜放到了2个锅里,但是只有1个炉子一样 

    如果上述条件都满足,有一个经验公式可以计算性能提升的比例,叫阿姆达尔定律: 

    速度提升比例 = 1/[(1-P)+(P/N)],其中P是可并行任务的比例,N是CPU核心数量 

    假设CPU核心是无限的,则公式简化为1/(1-P) 

    假设P达到了80%(已经非常高了),那么速度提升比例也只能达到5倍而已
    展开全文
  • Java编程为什么要用多线程,用多线程是不是会计算加快,加快的原理是什么
  • 72.为什么要用多线程

    2020-12-05 22:37:53
    2、为什么要用多线程?单线程效率低,同样的工作,在资源充足的情况下,单线程使用的时间比多线程更长。 没有多线程的话,更多的线程影响性能,需要更多内存,并且在操作系统之前操作麻烦,切换不太方便 多线程---...

    1、多线程 多个线程并发可以同时进行,线程互相独立,A线程可以先开始,B线程可以提前结束,A不影响B,B不影响A,各做各的路。

    2、为什么要用多线程?单线程效率低,同样的工作,在资源充足的情况下,单线程使用的时间比多线程更长。

    没有多线程的话,更多的线程影响性能,需要更多内存,并且在操作系统之前操作麻烦,切换不太方便

    多线程----》解决负载均衡问题,充分地利用CPU资源,提高运行效率

    3、多线程应用场景
    多个任务:1 复制多个文件,好家伙,一起来执行吧。2 腾讯管家,好家伙,清理杀毒升级一起来吧,我去休息一下,啪啪几分钟结束

    需要一些等待的任务 1 淘宝找商品的时候往下滑的时候,同时下面的图片,商品信息在加载 2 某些搜索,你输入第一个字的时候,下面就有信息内容出来了,还有关键字推荐等等功能

    需要后台在执行

    展开全文
  • java中为什么要用多线程 我们可以在计算机上运行各种计算机软件程序。每一个运行的程序可能包括多个独立运行的线程(Thread)。 线程(Thread)是一份独立运行的程序,有自己专用的运行栈。线程有可能和其他...

    java中为什么要用多线程

    我们可以在计算机上运行各种计算机软件程序。每一个运行的程序可能包括多个独立运行的线程(Thread)。
    线程(Thread)是一份独立运行的程序,有自己专用的运行栈。线程有可能和其他线程共享一些资源,比如,内存,文件,数据库等。
    当多个线程同时读写同一份共享资源的时候,可能会引起冲突。这时候,我们需要引入线程“同步”机制,即各位线程之间要有个先来后到,不能一窝蜂挤上去抢作一团。
    同步这个词是从英文synchronize(使同时发生)翻译过来的。我也不明白为什么要用这个很容易引起误解的词。既然大家都这么用,咱们也就只好这么将就。
    线程同步的真实意思和字面意思恰好相反。线程同步的真实意思,其实是“排队”:几个线程之间要排队,一个一个对共享资源进行操作,而不是同时进行操作。

    因此,关于线程同步,需要牢牢记住的第一点是:
                 线程同步就是线程排队。同步就是排队。线程同步的目的就是避免线程“同步”执行。这可真是个无聊的绕口令。
                 关于线程同步,需要牢牢记住的第二点是:
              “共享”这两个字。只有共享资源的读写访问才需要同步。如果不是共享资源,那么就根本没有同步的必要。
                 关于线程同步,需要牢牢记住的第三点是:
               只有“变量”才需要同步访问。如果共享的资源是固定不变的,那么就相当于“常量”,线程同时读取常量也不需要同步。至少一个线程修改共享资源,这样的情况下,线程之间就需要同步。
                关于线程同步,需要牢牢记住的第四点是:
    多个线程访问共享资源的代码有可能是同一份代码,也有可能是不同的代码;无论是否执行同一份代码,只要这些线程的代码访问同一份可变的共享资源,这些线程之间就需要同步。

    为了加深理解,下面举几个例子。
    有两个采购员,他们的工作内容是相同的,都是遵循如下的步骤:
    (1)到市场上去,寻找并购买有潜力的样品。
    (2)回到公司,写报告。
    这两个人的工作内容虽然一样,他们都需要购买样品,他们可能买到同样种类的样品,但是他们绝对不会购买到同一件样品,他们之间没有任何共享资源。所以,他们可以各自进行自己的工作,互不干扰。
    这两个采购员就相当于两个线程;两个采购员遵循相同的工作步骤,相当于这两个线程执行同一段代码。

    下面给这两个采购员增加一个工作步骤。采购员需要根据公司的“布告栏”上面公布的信息,安排自己的工作计划。
    这两个采购员有可能同时走到布告栏的前面,同时观看布告栏上的信息。这一点问题都没有。因为布告栏是只读的,这两个采购员谁都不会去修改布告栏上写的信息。

    下面增加一个角色。一个办公室行政人员这个时候,也走到了布告栏前面,准备修改布告栏上的信息。
    如果行政人员先到达布告栏,并且正在修改布告栏的内容。两个采购员这个时候,恰好也到了。这两个采购员就必须等待行政人员完成修改之后,才能观看修改后的信息。
    如果行政人员到达的时候,两个采购员已经在观看布告栏了。那么行政人员需要等待两个采购员把当前信息记录下来之后,才能够写上新的信息。
    上述这两种情况,行政人员和采购员对布告栏的访问就需要进行同步。因为其中一个线程(行政人员)修改了共享资源(布告栏)。而且我们可以看到,行政人员的工作流程和采购员的工作流程(执行代码)完全不同,但是由于他们访问了同一份可变共享资源(布告栏),所以他们之间需要同步。

    同步锁

    前面讲了为什么要线程同步,下面我们就来看如何才能线程同步。
    线程同步的基本实现思路还是比较容易理解的。我们可以给共享资源加一把锁,这把锁只有一把钥匙。哪个线程获取了这把钥匙,才有权利访问该共享资源。
    生活中,我们也可能会遇到这样的例子。一些超市的外面提供了一些自动储物箱。每个储物箱都有一把锁,一把钥匙。人们可以使用那些带有钥匙的储物箱,把东西放到储物箱里面,把储物箱锁上,然后把钥匙拿走。这样,该储物箱就被锁住了,其他人不能再访问这个储物箱。(当然,真实的储物箱钥匙是可以被人拿走复制的,所以不要把贵重物品放在超市的储物箱里面。于是很多超市都采用了电子密码锁。)
    线程同步锁这个模型看起来很直观。但是,还有一个严峻的问题没有解决,这个同步锁应该加在哪里?
    当然是加在共享资源上了。反应快的读者一定会抢先回答。
    没错,如果可能,我们当然尽量把同步锁加在共享资源上。一些比较完善的共享资源,比如,文件系统,数据库系统等,自身都提供了比较完善的同步锁机制。我们不用另外给这些资源加锁,这些资源自己就有锁。
    但是,大部分情况下,我们在代码中访问的共享资源都是比较简单的共享对象。这些对象里面没有地方让我们加锁。
    读者可能会提出建议:为什么不在每一个对象内部都增加一个新的区域,专门用来加锁呢?这种设计理论上当然也是可行的。问题在于,线程同步的情况并不是很普遍。如果因为这小概率事件,在所有对象内部都开辟一块锁空间,将会带来极大的空间浪费。得不偿失。
    于是,现代的编程语言的设计思路都是把同步锁加在代码段上。确切的说,是把同步锁加在“访问共享资源的代码段”上。这一点一定要记住,同步锁是加在代码段上的。
    同步锁加在代码段上,就很好地解决了上述的空间浪费问题。但是却增加了模型的复杂度,也增加了我们的理解难度。
    现在我们就来仔细分析“同步锁加在代码段上”的线程同步模型。
    首先,我们已经解决了同步锁加在哪里的问题。我们已经确定,同步锁不是加在共享资源上,而是加在访问共享资源的代码段上。
    其次,我们要解决的问题是,我们应该在代码段上加什么样的锁。这个问题是重点中的重点。这是我们尤其要注意的问题:访问同一份共享资源的不同代码段,应该加上同一个同步锁;如果加的是不同的同步锁,那么根本就起不到同步的作用,没有任何意义。
    这就是说,同步锁本身也一定是多个线程之间的共享对象。

    Java语言的synchronized关键字

    为了加深理解,举几个代码段同步的例子。
    不同语言的同步锁模型都是一样的。只是表达方式有些不同。这里我们以当前最流行的Java语言为例。Java语言里面用synchronized关键字给代码段加锁。整个语法形式表现为
    synchronized(同步锁) {
    // 访问共享资源,需要同步的代码段
    }

    这里尤其要注意的就是,同步锁本身一定要是共享的对象。

    … f1() {

    Object lock1 = new Object(); // 产生一个同步锁

    synchronized(lock1){
    // 代码段 A
    // 访问共享资源 resource1
    // 需要同步
    }
    }

    上面这段代码没有任何意义。因为那个同步锁是在函数体内部产生的。每个线程调用这段代码的时候,都会产生一个新的同步锁。那么多个线程之间,使用的是不同的同步锁。根本达不到同步的目的。
    同步代码一定要写成如下的形式,才有意义。

    public static final Object lock1 = new Object();

    … f1() {

    synchronized(lock1){ // lock1 是公用同步锁
    // 代码段 A
    // 访问共享资源 resource1
    // 需要同步
    }

    你不一定要把同步锁声明为static或者public,但是你一定要保证相关的同步代码之间,一定要使用同一个同步锁。
    讲到这里,你一定会好奇,这个同步锁到底是个什么东西。为什么随便声明一个Object对象,就可以作为同步锁?
    在Java里面,同步锁的概念就是这样的。任何一个Object Reference都可以作为同步锁。我们可以把Object Reference理解为对象在内存分配系统中的内存地址。因此,要保证同步代码段之间使用的是同一个同步锁,我们就要保证这些同步代码段的synchronized关键字使用的是同一个Object Reference,同一个内存地址。这也是为什么我在前面的代码中声明lock1的时候,使用了final关键字,这就是为了保证lock1的Object Reference在整个系统运行过程中都保持不变。
    一些求知欲强的读者可能想要继续深入了解synchronzied(同步锁)的实际运行机制。Java虚拟机规范中(你可以在google用“JVM Spec”等关键字进行搜索),有对synchronized关键字的详细解释。synchronized会编译成 monitor enter, … monitor exit之类的指令对。Monitor就是实际上的同步锁。每一个Object Reference在概念上都对应一个monitor。
    这些实现细节问题,并不是理解同步锁模型的关键。我们继续看几个例子,加深对同步锁模型的理解。

    public static final Object lock1 = new Object();

    … f1() {

    synchronized(lock1){ // lock1 是公用同步锁
    // 代码段 A
    // 访问共享资源 resource1
    // 需要同步
    }
    }

    … f2() {

    synchronized(lock1){ // lock1 是公用同步锁
    // 代码段 B
    // 访问共享资源 resource1
    // 需要同步
    }
    }

    上述的代码中,代码段A和代码段B就是同步的。因为它们使用的是同一个同步锁lock1。
    如果有10个线程同时执行代码段A,同时还有20个线程同时执行代码段B,那么这30个线程之间都是要进行同步的。
    这30个线程都要竞争一个同步锁lock1。同一时刻,只有一个线程能够获得lock1的所有权,只有一个线程可以执行代码段A或者代码段B。其他竞争失败的线程只能暂停运行,进入到该同步锁的就绪(Ready)队列。
    每一个同步锁下面都挂了几个线程队列,包括就绪(Ready)队列,待召(Waiting)队列等。比如,lock1对应的就绪队列就可以叫做lock1 - ready queue。每个队列里面都可能有多个暂停运行的线程。
    注意,竞争同步锁失败的线程进入的是该同步锁的就绪(Ready)队列,而不是后面要讲述的待召队列(Waiting Queue,也可以翻译为等待队列)。就绪队列里面的线程总是时刻准备着竞争同步锁,时刻准备着运行。而待召队列里面的线程则只能一直等待,直到等到某个信号的通知之后,才能够转移到就绪队列中,准备运行。
    成功获取同步锁的线程,执行完同步代码段之后,会释放同步锁。该同步锁的就绪队列中的其他线程就继续下一轮同步锁的竞争。成功者就可以继续运行,失败者还是要乖乖地待在就绪队列中。
    因此,线程同步是非常耗费资源的一种操作。我们要尽量控制线程同步的代码段范围。同步的代码段范围越小越好。我们用一个名词“同步粒度”来表示同步代码段的范围。
    同步粒度
    在Java语言里面,我们可以直接把synchronized关键字直接加在函数的定义上。
    比如。
    … synchronized … f1() {
    // f1 代码段
    }

    这段代码就等价于
    … f1() {
    synchronized(this){ // 同步锁就是对象本身
    // f1 代码段
    }
    }

    同样的原则适用于静态(static)函数
    比如。
    … static synchronized … f1() {
    // f1 代码段
    }

    这段代码就等价于
    …static … f1() {
    synchronized(Class.forName(…)){ // 同步锁是类定义本身
    // f1 代码段
    }
    }

    但是,我们要尽量避免这种直接把synchronized加在函数定义上的偷懒做法。因为我们要控制同步粒度。同步的代码段越小越好。synchronized控制的范围越小越好。
    我们不仅要在缩小同步代码段的长度上下功夫,我们同时还要注意细分同步锁。
    比如,下面的代码

    public static final Object lock1 = new Object();

    … f1() {

    synchronized(lock1){ // lock1 是公用同步锁
    // 代码段 A
    // 访问共享资源 resource1
    // 需要同步
    }
    }

    … f2() {

    synchronized(lock1){ // lock1 是公用同步锁
    // 代码段 B
    // 访问共享资源 resource1
    // 需要同步
    }
    }

    … f3() {

    synchronized(lock1){ // lock1 是公用同步锁
    // 代码段 C
    // 访问共享资源 resource2
    // 需要同步
    }
    }

    … f4() {

    synchronized(lock1){ // lock1 是公用同步锁
    // 代码段 D
    // 访问共享资源 resource2
    // 需要同步
    }
    }

    上述的4段同步代码,使用同一个同步锁lock1。所有调用4段代码中任何一段代码的线程,都需要竞争同一个同步锁lock1。
    我们仔细分析一下,发现这是没有必要的。
    因为f1()的代码段A和f2()的代码段B访问的共享资源是resource1,f3()的代码段C和f4()的代码段D访问的共享资源是resource2,它们没有必要都竞争同一个同步锁lock1。我们可以增加一个同步锁lock2。f3()和f4()的代码可以修改为:
    public static final Object lock2 = new Object();

    … f3() {

    synchronized(lock2){ // lock2 是公用同步锁
    // 代码段 C
    // 访问共享资源 resource2
    // 需要同步
    }
    }

    … f4() {

    synchronized(lock2){ // lock2 是公用同步锁
    // 代码段 D
    // 访问共享资源 resource2
    // 需要同步
    }
    }

    这样,f1()和f2()就会竞争lock1,而f3()和f4()就会竞争lock2。这样,分开来分别竞争两个锁,就可以大大较少同步锁竞争的概率,从而减少系统的开销。

    信号量

    同步锁模型只是最简单的同步模型。同一时刻,只有一个线程能够运行同步代码。
    有的时候,我们希望处理更加复杂的同步模型,比如生产者/消费者模型、读写同步模型等。这种情况下,同步锁模型就不够用了。我们需要一个新的模型。这就是我们要讲述的信号量模型。
    信号量模型的工作方式如下:线程在运行的过程中,可以主动停下来,等待某个信号量的通知;这时候,该线程就进入到该信号量的待召(Waiting)队列当中;等到通知之后,再继续运行。
    很多语言里面,同步锁都由专门的对象表示,对象名通常叫Monitor。
    同样,在很多语言中,信号量通常也有专门的对象名来表示,比如,Mutex,Semphore。
    信号量模型要比同步锁模型复杂许多。一些系统中,信号量甚至可以跨进程进行同步。另外一些信号量甚至还有计数功能,能够控制同时运行的线程数。
    我们没有必要考虑那么复杂的模型。所有那些复杂的模型,都是最基本的模型衍生出来的。只要掌握了最基本的信号量模型——“等待/通知”模型,复杂模型也就迎刃而解了。
    我们还是以Java语言为例。Java语言里面的同步锁和信号量概念都非常模糊,没有专门的对象名词来表示同步锁和信号量,只有两个同步锁相关的关键字——volatile和synchronized。
    这种模糊虽然导致概念不清,但同时也避免了Monitor、Mutex、Semphore等名词带来的种种误解。我们不必执着于名词之争,可以专注于理解实际的运行原理。
    在Java语言里面,任何一个Object Reference都可以作为同步锁。同样的道理,任何一个Object Reference也可以作为信号量。
    Object对象的wait()方法就是等待通知,Object对象的notify()方法就是发出通知。
    具体调用方法为
    (1)等待某个信号量的通知
    public static final Object signal = new Object();

    … f1() {
    synchronized(singal) { // 首先我们要获取这个信号量。这个信号量同时也是一个同步锁

    // 只有成功获取了signal这个信号量兼同步锁之后,我们才可能进入这段代码
    signal.wait(); // 这里要放弃信号量。本线程要进入signal信号量的待召(Waiting)队列

    // 可怜。辛辛苦苦争取到手的信号量,就这么被放弃了

    // 等到通知之后,从待召(Waiting)队列转到就绪(Ready)队列里面
    // 转到了就绪队列中,离CPU核心近了一步,就有机会继续执行下面的代码了。
    // 仍然需要把signal同步锁竞争到手,才能够真正继续执行下面的代码。命苦啊。

    }
    }

    需要注意的是,上述代码中的signal.wait()的意思。signal.wait()很容易导致误解。signal.wait()的意思并不是说,signal开始wait,而是说,运行这段代码的当前线程开始wait这个signal对象,即进入signal对象的待召(Waiting)队列。

    (2)发出某个信号量的通知
    … f2() {
    synchronized(singal) { // 首先,我们同样要获取这个信号量。同时也是一个同步锁。

    // 只有成功获取了signal这个信号量兼同步锁之后,我们才可能进入这段代码
    signal.notify(); // 这里,我们通知signal的待召队列中的某个线程。

    // 如果某个线程等到了这个通知,那个线程就会转到就绪队列中
    // 但是本线程仍然继续拥有signal这个同步锁,本线程仍然继续执行
    // 嘿嘿,虽然本线程好心通知其他线程,
    // 但是,本线程可没有那么高风亮节,放弃到手的同步锁
    // 本线程继续执行下面的代码

    }
    }

    需要注意的是,signal.notify()的意思。signal.notify()并不是通知signal这个对象本身。而是通知正在等待signal信号量的其他线程。

    以上就是Object的wait()和notify()的基本用法。
    实际上,wait()还可以定义等待时间,当线程在某信号量的待召队列中,等到足够长的时间,就会等无可等,无需再等,自己就从待召队列转移到就绪队列中了。
    另外,还有一个notifyAll()方法,表示通知待召队列里面的所有线程。
    这些细节问题,并不对大局产生影响。

    绿色线程

    绿色线程(Green Thread)是一个相对于操作系统线程(Native Thread)的概念。
    操作系统线程(Native Thread)的意思就是,程序里面的线程会真正映射到操作系统的线程,线程的运行和调度都是由操作系统控制的
    绿色线程(Green Thread)的意思是,程序里面的线程不会真正映射到操作系统的线程,而是由语言运行平台自身来调度。
    当前版本的Python语言的线程就可以映射到操作系统线程。当前版本的Ruby语言的线程就属于绿色线程,无法映射到操作系统的线程,因此Ruby语言的线程的运行速度比较慢。
    难道说,绿色线程要比操作系统线程要慢吗?当然不是这样。事实上,情况可能正好相反。Ruby是一个特殊的例子。线程调度器并不是很成熟。
    目前,线程的流行实现模型就是绿色线程。比如,stackless Python,就引入了更加轻量的绿色线程概念。在线程并发编程方面,无论是运行速度还是并发负载上,都优于Python。
    另一个更著名的例子就是ErLang(爱立信公司开发的一种开源语言)。
    ErLang的绿色线程概念非常彻底。ErLang的线程不叫Thread,而是叫做Process。这很容易和进程混淆起来。这里要注意区分一下。
    ErLang Process之间根本就不需要同步。因为ErLang语言的所有变量都是final的,不允许变量的值发生任何变化。因此根本就不需要同步。
    final变量的另一个好处就是,对象之间不可能出现交叉引用,不可能构成一种环状的关联,对象之间的关联都是单向的,树状的。因此,内存垃圾回收的算法效率也非常高。这就让ErLang能够达到Soft Real Time(软实时)的效果。这对于一门支持内存垃圾回收的语言来说,可不是一件容易的事情。
    展开全文
  • Java为什么要用多线程

    千次阅读 2018-09-05 00:16:55
    用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现。说这个话其实只有一半对,因为反应“多角色”的程序代码,最起码每个角色给他一个线程吧,否则连实际场景都无法...

    用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现。说这个话其实只有一半对,因为反应“多角色”的程序代码,最起码每个角色要给他一个线程吧,否则连实际场景都无法模拟,当然也没法说能用单线程来实现:比如最常见的“生产者,消费者模型”。

    就例如一个网络爬虫的功能,有10亿数据,假如一条请求花费0.1秒,因为时间有限,所以你要尽量提升开发效率,你就需要好多的服务器,大家也都知道,每台服务器的价钱都是成本,这么庞大的成本显然不切实际。我们只能想办法从自身提升效率。

    假如一个请求花费0.1秒,你处理他的请求只需要大约1毫秒,其实百分之99的时间都已经浪费了,所以,我想可以理论上开辟100个线程请求数据,这样CPU就没有任何浪费。当然,也只是理论上,实际上,线程之间的切换也是需要开销的,所以不可能开辟这么多的线程,不过开辟几个线程是很不错的选择。

    线程,一般就是在解决CPU浪费资源时才会用到。

    这就是为什么要用到线程。

    展开全文
  • 在介绍多线程的时候,我们首先知道什么是线程,而了解线程还要了解进程。 1.进程:一个正在执行中的程序,每个进程执行都有一个执行顺序,该顺序是一个执行路径,或者是一个控制单元(个人偏向这种 )。 2.线程...
  • 以前我认为多线程的作用就是提升性能。实际上,多线程并不一定能提升性能(甚至还会降低性能);多线程也不只是为了提升性能。多线程主要有以下的应用场景:  1、避免阻塞(异步调用)  单个线程中的程序,是顺序...
  • 为什么要用多线程 让计算机”同时”做多件事情,节约时间 后台运行程序,提高程序的运行效率,也不会使主界面出现无响应的情况. 多线程可以让一个程序”同时”处理多个事情. 计算机cpu大部分时间处于空闲状态,...
  • 实现特定目标或解决特定问题而计算机语言编写的命令序列的集合。所以程序实际上就是静态的代码,程序人生,代码人生 2、进程 进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度...
  • 为什么要同步? 线程彼此相互独立,对于同一数据,多线程都可以读取,就会产生异常和矛盾; 比如LOL:Hero类,一个对象为盖伦Gareen,血量1000,一个线程加血addHp(),一个线程减血reduceHp() 正常情况下: 血量为...
  • 2、每个CPU在同一时间只能执行一个线程(在单核CPU下的多线程其实都只是并发,不是并行,并发和并行从宏观上来讲都是同时处理多路请求的概念。但并发和并行又有区别,并行是指两个或者多个事件在同一时刻发生;而并发...
  • /** * Created by hcmony on 2017/8/31. */ public class Test{ ... //多线程要执行的方法 public static void getInt(int i){ System.out.println(Thread.currentThread().getName()+"-"+i); } static
  • 许多情况下,在一个程序中使用多线程是有益处的。下面是一些深度的观察,为什么是有好处的。 与用户的更好交互(Better Interaction with the User) 如果只有一个线程,那一个程序在同一时刻只能做一件事情。...
  • 自我开始工作来,多线程这个概念一直缠绕不去,几乎是不懂得多线程就是什么令人感到耻辱的事情,但是说归说,究竟为什么要用多线程,总得弄个清楚。 多线程的主要是平衡CPU空时间片与繁重任务的作用,提高利用率。...
  • 要用多线程 https://zhidao.baidu.com/question/1703254723230484300.html 使用多线程是为了提高程序运行的效率。假如有一个程序,要求用户输入多个算式,计算出结果,并分别打印到屏幕上。如果用户一直没有输入...
  • 一、为什么要使用线程池多线程的情况下确实可以最大限度发挥多核处理器的计算能力,提高系统的吞吐量和性能。但是如果随意使用多线程,对系统的性能反而有不利影响。比如下面的情况:创建线程是需要时间的,假设线程...
  • 多线程为什么能提高效率(I/O密集):一个线程可以操作很多内容--获得IO资源---加工IO资源,如果使用多线程去操作一块io资源,虽然有gil,但是在很短的时间内,io资源能分给很多线程,然后剩余的io资源的加工操作,...
  • 小编典典我不知道何时应该在Java开发中使用多线程,以及使用它的逻辑/原因。在不同情况下如何提供帮助?您应出于多种原因将程序更改使用线程。该程序将以更快的速度运行并更好地利用您所运行的多个CPU /内核体系...
  • 为什么要使用多线程? 这里举个例子: 在百度云时(只能单线程运行的情况) 在使用百度云时(可以多线程的运行情况) 总结:使用多线程可以提高程序的效率 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,347
精华内容 1,338
关键字:

为什么要用多线程