精华内容
下载资源
问答
  • 2017-04-03 17:42:17
                    <!-- 正文开始 -->
        <div id="sina_keyword_ad_area2" class="articalContent   ">
            <div>
    

    如果你的应用程序需要采取以下的操作,那么你尽可在编程的时候考虑多线程机制:



    连续的操作,需要花费忍无可忍的过长时间才可能完成

    并行计算

    为了等待网络、文件系统、用户或其他I/O响应而耗费大量的执行时间

    所以说,在动手之前,先保证自己的应用程序中是否出现了以上3种情形。


    为什么需要多线程(解释何时考虑使用线程)

    从用户的角度考虑,就是为了得到更好的系统服务;从程序自身的角度考虑,就是使目标任务能够尽可能快的完成,更有效的利用系统资源。综合考虑,一般以下场合需要使用多线程:

    1、 程序包含复杂的计算任务时

    主要是利用多线程获取更多的CPU时间(资源)。

    2、 处理速度较慢的外围设备

    比如:打印时。再比如网络程序,涉及数据包的收发,时间因素不定。使用独立的线程处理这些任务,可使程序无需专门等待结果。

    3、 程序设计自身的需要

    WINDOWS系统是基于消息循环的抢占式多任务系统,为使消息循环系统不至于阻塞,程序需要多个线程的来共同完成某些任务。



    每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。进程也可能是整个程序或者是部分程序的动态执行。线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。也可以把它理解为代码运行的上下文。所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务。通常由操作系统负责多个线程的调度和执行。



      什么是多线程?



      多线程是为了使得多个线程并行的工作以完成多项任务,以提高系统的效率。线程是在同一时间需要完成多项任务的时候被实现的。



      使用线程的好处有以下几点:



      ·使用线程可以把占据长时间的程序中的任务放到后台去处理



      ·用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度



      ·程序的运行速度可能加快



      ·在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。



      还有其他很多使用多线程的好处,这里就不一一说明了。



      一些线程模型的背景



      我们可以重点讨论一下在Win32环境中常用的一些模型。



      ·单线程模型



      在这种线程模型中,一个进程中只能有一个线程,剩下的进程必须等待当前的线程执行完。这种模型的缺点在于系统完成一个很小的任务都必须占用很长的时间。



      ·块线程模型(单线程多块模型STA)



      这种模型里,一个程序里可能会包含多个执行的线程。在这里,每个线程被分为进程里一个单独的块。每个进程可以含有多个块,可以共享多个块中的数据。程序规定了每个块中线程的执行时间。所有的请求通过Windows消息队列进行串行化,这样保证了每个时刻只能访问一个块,因而只有一个单独的进程可以在某一个时刻得到执行。这种模型比单线程模型的好处在于,可以响应同一时刻的多个用户请求的任务而不只是单个用户请求。但它的性能还不是很好,因为它使用了串行化的线程模型,任务是一个接一个得到执行的。



      ·多线程块模型(自由线程块模型)



      多线程块模型(MTA)在每个进程里只有一个块而不是多个块。这单个块控制着多个线程而不是单个线程。这里不需要消息队列,因为所有的线程都是相同的块的一个部分,并且可以共享。这样的程序比单线程模型和STA的执行速度都要块,因为降低了系统的负载,因而可以优化来减少系统idle的时间。这些应用程序一般比较复杂,因为程序员必须提供线程同步以保证线程不会并发的请求相同的资源,因而导致竞争情况的发生。这里有必要提供一个锁机制。但是这样也许会导致系统死锁的发生。







    转自: http://blog.sina.com.cn/s/blog_4ee24ced0101375f.html
    更多相关内容
  • Java:多线程:到底什么时候用多线程

    万次阅读 多人点赞 2018-09-30 16:27:29
    系统接受实现多用户多请求的高并发时,通过多线程来实现。   二、线程后台处理大任务 一个程序是线性执行的。如果程序执行到要花大量时间处理的任务时,那主程序就得等待其执行完才能继续执行下面的...

    一、高并发

    系统接受实现多用户多请求的高并发时,通过多线程来实现。

     

    二、线程后台处理大任务

    一个程序是线性执行的。如果程序执行到要花大量时间处理的任务时,那主程序就得等待其执行完才能继续执行下面的。那用户就不得不等待它执行完。

    这时候可以开线程把花大量时间处理的任务放在线程处理,这样线程在后台处理时,主程序也可以继续执行下去,用户就不需要等待。线程执行完后执行回调函数。

     

    三、大任务

    大任务处理起来比较耗时,这时候可以起到多个线程并行加快处理(例如:分片上传)。

     

    连续的操作,需要花费忍无可忍的过长时间才可能完成
    并行计算
    为了等待网络、文件系统、用户或其他I/O响应而耗费大量的执行时间
    所以说,在动手之前,先保证自己的应用程序中是否出现了以上3种情形。

    文章一:

    我想大多数人在学习多线程时都会对此问题有所顾虑,尽管多线程的概念不难理解,那我们什么时候该用它呢?在大多数情况下,我们写了程序,发现有时必须使用多线程才能得到理想的运行结果,于是我们按照资料调用相关的线程类库或API改善程序,并使其正常运行;但是,到底存不存在一种判断依据,能够明确的指导我们正确地使用多线程机制来解决问题呢?笔者对此进行了一番思考,在此说说我的想法以供参考。

        在开始之前,先引入几个问题,这些问题最终都会在这篇文章里找到答案。

    问题情景[0]:设计一个简单的UI:包括一个文本标签和一个按钮,在点击按钮时文本显示由0~10的增长,每秒增长量为1。

    问题情景[1]:某同学编写的坦克大战程序中,每一个坦克和子弹均使用一个独立的线程,这是否合理?(当然不合理。。。)如果是你,你会怎么编写这个程序?

     

        笔者认为,多线程的使用离不开“阻塞”这个概念,不过,我想先对这个概念加以扩充,首先先来回想一下阻塞概念原本的意思,简单的说,就是程序运行到某些函数或过程后等待某些事件发生而暂时停止CPU占用的情况;也就是说,是一种CPU闲等状态,不过有时我们使用多线程并不一定是保持闲等时的程序响应,例如在追求高性能的程序中,某条线程在进行高强度的运算,此时若对运算性能不满意,我们也许会再启动若干条运算线程(当然,是在CPU有运算余力的情况下),此时,高强度运算应该归为一种“忙等”状态。

        说到这,多线程归根究底是为了解决"等"的问题,那我们这样定义一个阻塞过程:程序运行该过程所消耗的时间有可能在运行上下文间产生明显的卡顿;这里使用“可能”是因为有些情况下,诸如Socket通信,如果数据源源不断的进入,那么阻塞的时间可能非常小,但我们还是使用了一条线程(nio另说)来处理它,因为我们无法保证数据到来的持续性和有效性;"卡顿"带有主观臆想,也就是说是使用者(人或一些自动化程序)不可接受的。

    接下来,对什么时候使用多线程做一个回答:编写程序过程中需要使用某些阻塞过程时,我们才使用多线程,或者更进一步讲,使用多线程的目的是对阻塞过程中的实际阻塞的抽象提取。前半句话应该很好理解,而后面的一句虽然不太好懂,不过它对一个程序应具有的合理线程数量进行了阐释(这点接下来解释)。

     

    好了,接下来我们回顾一些两个问题,并对它们做出解答:

    问题情景[0]

        为了方便表达,笔者在此采用伪Java代码来阐释解答过程。首先我们有一个Label textShower用于显示文本,Button textChanger作为点击的按钮

    这个问题是笔者还是一名小菜时遇到的,当时笔者是这么写的:

    public class MyFrame
    {
        Label textShower;
        Button textChanger;
        public MyFrame//实例化等省略
        {
           textChanger.setOnClickListener(new OnClickListener(){
    	public void onClick(MouseEvent e){
    		for(int i = 1;i <= 10;i++){
    			textShower.setText(i+"");//设置文字
    			Thread.sleep(1000);//等待一秒
    		}
    	}
    	});
        }
    }
    

     

        程序的执行结果是点击后10秒没有响应,然后数值被设定为10;现在知道了,是由于AWT消息线程同时负责着图像的绘制刷新操作,而Thread.sleep属于之前的阻塞过程,导致画面停止响应。

    当时老师是这么教给我的:

     

    public class MyFrame
    {
        Label textShower;
        Button textChanger;
        public MyFrame//实例化等省略
        {
           textChanger.setOnClickListener(new OnClickListener(){
    	public void onClick(MouseEvent e){
    	new Thread(){
    		public void run()
    		{
    			for(int i = 0;i < 10;i++){
    				textShower.setText(i+"");//设置文字
    				Thread.sleep(1000);//等待一秒
    			}	
    		}
    	}.start();
    	}
    	});
        }
    }
    

     

        当然,这样确实能够满足题目要求,我也因此开心了一阵,不过不久我就有了新的问题:每按一次按钮产生一个线程是否合理呢?如果这样的文本组合再多几个,我也要创建更多的线程吗?要是使用者是个熊孩子来这里一通狂按这程序还受得了么....

        后来,在面向对象思想深入人心后,稍微懂面向对象的人都会知道使用抽象来简化程序,只不过在上面的问题中,我们需要抽象的不是具体的实体,而是“实际阻塞”这种抽象概念。

        在上面的代码中,笔者写的第一个onClick函数属于一个阻塞过程,其中sleep属于“实际阻塞”。

        而改版的代码中,只是使用多线程将原本的阻塞过程变为了非阻塞过程,实际上是使用了一个独立的线程将整个阻塞过程包含在内,并没有做任何的抽象。

    问题情景[1]:在这个问题中,将主要讨论实际阻塞的抽象和合理线程数量的问题。

        这个情景是不久前一位网友问我的,他的毕业设计是编写一个坦克大战的游戏,在编的差不多的时候,突然想到每一辆坦克、每一发子弹都是用单独的线程不是很合理,问我如何改进。用这个例子说明实际阻塞的抽象再合适不过了,我们先看看他写的代码片段:

    坦克类:

     

    public class Tank extends Thread{
    	float x;//这里以横向移动为例子,只写一个属性
    	float speed = 1f;
    	public void run()
    	{
    		drawtank();//清除上一次的绘制,根据横坐标x画一个坦克
    		x+=speed;
    		Thread.sleep(17);//约合一秒60次
    	}
    }
    


    子弹类:

    public class Bullet extends Thread{
    	float x;//这里以横向移动为例子,只写一个属性
    	float speed = 10f;
    	public void run()
    	{
    		drawbullet();//清除上一次的绘制,根据横坐标x画一个子弹
    		x+=speed;
    		Thread.sleep(17);//约合一秒60次
    	}
    }
    

     


        其实这样异步的绘制会使画面产生明显的抖动,而且用于同步的逻辑也十分复杂,并不是一个好的方案。

     

    其实上面两个类中的run方法中,只有sleep属于实际阻塞,也就是说是可以被抽象出来的,我们只要一个线程,每过17毫秒执行一些列非阻塞过程即可。

    上述过程中,绘制及坐标的运算属于非阻塞过程,我们将其抽象为一个接口:

    public interface Drawable
    {
    	public void draw();
    }
    

    之后我们书写抽象实际阻塞的线程类:

     

     

    public class BlockThread extends Thread 
    {
    	Collection<Drawable> c = new Collection<Drawable>();
    	public void run()
    	{
    		for(Drawable d:c)
    		{
    			d.draw();
    		}
    		Thread.sleep(17);
    	}
    	//封装对成员c的同步CRUD不赘述
    	public void addDrawable(Drawable d);
    	public void removeDrawable(Drawable d);
    	...
    }
    

    最后,坦克和子弹的改动:
    坦克类:

    public class Tank implements Drawable{
    	float x;//这里以横向移动为例子,只写一个属性
    	float speed = 1f;
    	@Override
    	public void draw()
    	{
    		drawtank();//清除上一次的绘制,根据横坐标x画一个坦克
    		x+=speed;
    	}
    }
    

     

    子弹类:

    public class Bullet implements Drawable{
    	float x;//这里以横向移动为例子,只写一个属性
    	float speed = 10f;
    	@Override
    	public void draw()
    	{
    		drawbullet();//清除上一次的绘制,根据横坐标x画一个子弹
    		x+=speed;
    	}
    }
    

     

        我们可以发现:原有的实际阻塞过程已经被抽象到一个线程之中,而非阻塞过程,诸如绘制和坐标运算依然作为方法保留到对应类中,这样,无论有多少坦克和炮弹,只要非阻塞过程的运算压总和力不至于逼近阻塞的程度,使用一个线程即可完成所有工作。

     

        而且,如果想要添加游戏元素,例如其他类型的子弹,只需要实现Drawable接口即可。

        写到这,UI的问题也就解决了,诸如sleep这样纯粹延时的阻塞非常容易抽象,我们可以如法炮制,使用一个线程解决所有的数值延时自增的问题。但并不是所有实际阻塞都易于抽象,如socket.read(byte[] b);这样的方法显然没有抽象的余地,因此才引出后来的nio方案。

     

        最后,我们对什么时候使用多线程,以及使用线程的数量做一个总结:在编写程序时,遇到了阻塞过程而不想使整个程序停止响应时,应使用多线程;一个程序的合理线程数量取决于对实际阻塞的抽象程度。

    原文参考:https://blog.csdn.net/shuzhe66/article/details/25484195

     

     

    文章二:

    如果你的应用程序需要采取以下的操作,那么你尽可在编程的时候考虑多线程机制:

    连续的操作,需要花费忍无可忍的过长时间才可能完成
    并行计算
    为了等待网络、文件系统、用户或其他I/O响应而耗费大量的执行时间
    所以说,在动手之前,先保证自己的应用程序中是否出现了以上3种情形。

    为什么需要多线程(解释何时考虑使用线程)
    从用户的角度考虑,就是为了得到更好的系统服务;从程序自身的角度考虑,就是使目标任务能够尽可能快的完成,更有效的利用系统资源。综合考虑,一般以下场合需要使用多线程:
    1、 程序包含复杂的计算任务时
    主要是利用多线程获取更多的CPU时间(资源)。
    2、 处理速度较慢的外围设备
    比如:打印时。再比如网络程序,涉及数据包的收发,时间因素不定。使用独立的线程处理这些任务,可使程序无需专门等待结果。
    3、 程序设计自身的需要
    WINDOWS系统是基于消息循环的抢占式多任务系统,为使消息循环系统不至于阻塞,程序需要多个线程的来共同完成某些任务。

    每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。进程也可能是整个程序或者是部分程序的动态执行。线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。也可以把它理解为代码运行的上下文。所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务。通常由操作系统负责多个线程的调度和执行。

      什么是多线程?

      多线程是为了使得多个线程并行的工作以完成多项任务,以提高系统的效率。线程是在同一时间需要完成多项任务的时候被实现的。

      使用线程的好处有以下几点:

      ·使用线程可以把占据长时间的程序中的任务放到后台去处理

      ·用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度

      ·程序的运行速度可能加快

      ·在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。

      还有其他很多使用多线程的好处,这里就不一一说明了。

      一些线程模型的背景

      我们可以重点讨论一下在Win32环境中常用的一些模型。

      ·单线程模型

      在这种线程模型中,一个进程中只能有一个线程,剩下的进程必须等待当前的线程执行完。这种模型的缺点在于系统完成一个很小的任务都必须占用很长的时间。

      ·块线程模型(单线程多块模型STA)

      这种模型里,一个程序里可能会包含多个执行的线程。在这里,每个线程被分为进程里一个单独的块。每个进程可以含有多个块,可以共享多个块中的数据。程序规定了每个块中线程的执行时间。所有的请求通过Windows消息队列进行串行化,这样保证了每个时刻只能访问一个块,因而只有一个单独的进程可以在某一个时刻得到执行。这种模型比单线程模型的好处在于,可以响应同一时刻的多个用户请求的任务而不只是单个用户请求。但它的性能还不是很好,因为它使用了串行化的线程模型,任务是一个接一个得到执行的。

      ·多线程块模型(自由线程块模型)

      多线程块模型(MTA)在每个进程里只有一个块而不是多个块。这单个块控制着多个线程而不是单个线程。这里不需要消息队列,因为所有的线程都是相同的块的一个部分,并且可以共享。这样的程序比单线程模型和STA的执行速度都要块,因为降低了系统的负载,因而可以优化来减少系统idle的时间。这些应用程序一般比较复杂,因为程序员必须提供线程同步以保证线程不会并发的请求相同的资源,因而导致竞争情况的发生。这里有必要提供一个锁机制。但是这样也许会导致系统死锁的发生。

    原文参考:http://blog.sina.com.cn/s/blog_4ee24ced0101375f.html

     

    文章三:

    “IO操作的DMA(Direct Memory Access)模式”开始讲起。DMA即直接内存访问,是一种不经过CPU而直接进行内存数据存储的数据交换模式。通过DMA的数据交换几乎可以不损耗CPU的资源。在硬件中,硬盘、网卡、声卡、显卡等都有DMA功能。CLR所提供的异步编程模型就是让我们充分利用硬件的DMA功能来释放CPU的压力。

    多线程使用的主要目的在于:


    1、吞吐量:你做WEB,容器帮你做了多线程,但是他只能帮你做请求层面的。简单的说,可能就是一个请求一个线程。或多个请求一个线程。如果是单线程,那同时只能处理一个用户的请求。

    2、伸缩性:也就是说,你可以通过增加CPU核数来提升性能。如果是单线程,那程序执行到死也就利用了单核,肯定没办法通过增加CPU核数来提升性能。

    鉴于你是做WEB的,第1点可能你几乎不涉及。那这里我就讲第二点吧。

    --举个简单的例子:
    假设有个请求,这个请求服务端的处理需要执行3个很缓慢的IO操作(比如数据库查询或文件查询),那么正常的顺序可能是(括号里面代表执行时间):
    a、读取文件1  (10ms)
    b、处理1的数据(1ms)
    c、读取文件2  (10ms)
    d、处理2的数据(1ms)
    e、读取文件3  (10ms)
    f、处理3的数据(1ms)
    g、整合1、2、3的数据结果 (1ms)
    单线程总共就需要34ms。
    那如果你在这个请求内,把ab、cd、ef分别分给3个线程去做,就只需要12ms了。

    所以多线程不是没怎么用,而是,你平常要善于发现一些可优化的点。然后评估方案是否应该使用。
    假设还是上面那个相同的问题:但是每个步骤的执行时间不一样了。
    a、读取文件1  (1ms)
    b、处理1的数据(1ms)
    c、读取文件2  (1ms)
    d、处理2的数据(1ms)
    e、读取文件3  (28ms)
    f、处理3的数据(1ms)
    g、整合1、2、3的数据结果 (1ms)
    单线程总共就需要34ms。
    如果还是按上面的划分方案(上面方案和木桶原理一样,耗时取决于最慢的那个线程的执行速度),在这个例子中是第三个线程,执行29ms。那么最后这个请求耗时是30ms。比起不用单线程,就节省了4ms。但是有可能线程调度切换也要花费个1、2ms。因此,这个方案显得优势就不明显了,还带来程序复杂度提升。不太值得。

    那么现在优化的点,就不是第一个例子那样的任务分割多线程完成。而是优化文件3的读取速度。
    可能是采用缓存和减少一些重复读取。
    首先,假设有一种情况,所有用户都请求这个请求,那其实相当于所有用户都需要读取文件3。那你想想,100个人进行了这个请求,相当于你花在读取这个文件上的时间就是28×100=2800ms了。那么,如果你把文件缓存起来,那只要第一个用户的请求读取了,第二个用户不需要读取了,从内存取是很快速的,可能1ms都不到。

     

    不使用线程池的缺点

    有些开发者图省事,遇到需要多线程处理的地方,直接new Thread(...).start(),对于一般场景是没问题的,但如果是在并发请求很高的情况下,就会有些隐患:

    • 新建线程的开销。线程虽然比进程要轻量许多,但对于JVM来说,新建一个线程的代价还是挺大的,决不同于新建一个对象
    • 资源消耗量。没有一个池来限制线程的数量,会导致线程的数量直接取决于应用的并发量,这样有潜在的线程数据巨大的可能,那么资源消耗量将是巨大的
    • 稳定性。当线程数量超过系统资源所能承受的程度,稳定性就会成问题

    原文参考:https://blog.csdn.net/wujizkm/article/details/50651808

    文章四:

    在不希望等待一个耗时任务的返回结果时,会涉及到多线程,比如下载三个文件,可以在当前线程开启三个新线程分别执行,而不影响当前线程继续运行
    在spring的项目中,一个请求就是一个线程

    为什么可以多线程以及多线程有什么意义?然后你就知道自己什么时候需要用到了。

    CPU从以前的单CPU单核发展为多核、多CPU、重核等,这是多线程可以实现的基础

    多线程即意味着多个任务(子任务)可以同时执行(当然,只是宏观上),若是单线程,只能一个接一个顺序执行。
    使用多线程,最直接的目的就是希望任务完成的更快。

    当然,多线程也会产生一些不希望看到的问题

    对java的线程类Thread来进行说明:
    1:Thread是针对是java其本身所具有的,但并不能说其没有调用操作系统,其最底层的时间片调度是按照操作系统来执行的。
    Thread下可以创建Thread,
    2个Thread在一定条件下也可以相互调用。
    根据以上特点可以总结认为java中的线程能让高级程序员更好的对庞大和复杂的数据流进行拆分,重组从而减低各个环节性能需求,通过增加各项负荷达到系统资源分配的最优值

    也就是为了更快

    对于处理时间短的服务或者启动频率高的要用单线程,相反用多线程!

     

    展开全文
  • 系统接受实现多用户多请求的高并发时,通过多线程来实现。 二、线程后台处理大任务 一个程序是线性执行的。如果程序执行到要花大量时间处理的任务时,那主程序就得等待其执行完才能继续执行下面的。那用户就不得...

    本文转自:花和尚也有春天

    原文地址:https://blog.csdn.net/weixin_38750084/article/details/82911048

    一、高并发

    系统接受实现多用户多请求的高并发时,通过多线程来实现。

     

    二、线程后台处理大任务

    一个程序是线性执行的。如果程序执行到要花大量时间处理的任务时,那主程序就得等待其执行完才能继续执行下面的。那用户就不得不等待它执行完。

    这时候可以开线程把花大量时间处理的任务放在线程处理,这样线程在后台处理时,主程序也可以继续执行下去,用户就不需要等待。线程执行完后执行回调函数。

     

    三、大任务

    大任务处理起来比较耗时,这时候可以起到多个线程并行加快处理(例如:分片上传)。

    连续的操作,需要花费忍无可忍的过长时间才可能完成
    并行计算
    为了等待网络、文件系统、用户或其他I/O响应而耗费大量的执行时间
    所以说,在动手之前,先保证自己的应用程序中是否出现了以上3种情形。

    文章一:

    我想大多数人在学习多线程时都会对此问题有所顾虑,尽管多线程的概念不难理解,那我们什么时候该用它呢?在大多数情况下,我们写了程序,发现有时必须使用多线程才能得到理想的运行结果,于是我们按照资料调用相关的线程类库或API改善程序,并使其正常运行;但是,到底存不存在一种判断依据,能够明确的指导我们正确地使用多线程机制来解决问题呢?笔者对此进行了一番思考,在此说说我的想法以供参考。

        在开始之前,先引入几个问题,这些问题最终都会在这篇文章里找到答案。

    问题情景[0]:设计一个简单的UI:包括一个文本标签和一个按钮,在点击按钮时文本显示由0~10的增长,每秒增长量为1。

    问题情景[1]:某同学编写的坦克大战程序中,每一个坦克和子弹均使用一个独立的线程,这是否合理?(当然不合理。。。)如果是你,你会怎么编写这个程序?

     

        笔者认为,多线程的使用离不开“阻塞”这个概念,不过,我想先对这个概念加以扩充,首先先来回想一下阻塞概念原本的意思,简单的说,就是程序运行到某些函数或过程后等待某些事件发生而暂时停止CPU占用的情况;也就是说,是一种CPU闲等状态,不过有时我们使用多线程并不一定是保持闲等时的程序响应,例如在追求高性能的程序中,某条线程在进行高强度的运算,此时若对运算性能不满意,我们也许会再启动若干条运算线程(当然,是在CPU有运算余力的情况下),此时,高强度运算应该归为一种“忙等”状态。

        说到这,多线程归根究底是为了解决"等"的问题,那我们这样定义一个阻塞过程:程序运行该过程所消耗的时间有可能在运行上下文间产生明显的卡顿;这里使用“可能”是因为有些情况下,诸如Socket通信,如果数据源源不断的进入,那么阻塞的时间可能非常小,但我们还是使用了一条线程(nio另说)来处理它,因为我们无法保证数据到来的持续性和有效性;"卡顿"带有主观臆想,也就是说是使用者(人或一些自动化程序)不可接受的。

    接下来,对什么时候使用多线程做一个回答:编写程序过程中需要使用某些阻塞过程时,我们才使用多线程,或者更进一步讲,使用多线程的目的是对阻塞过程中的实际阻塞的抽象提取。前半句话应该很好理解,而后面的一句虽然不太好懂,不过它对一个程序应具有的合理线程数量进行了阐释(这点接下来解释)。

     

    好了,接下来我们回顾一些两个问题,并对它们做出解答:

    问题情景[0]

        为了方便表达,笔者在此采用伪Java代码来阐释解答过程。首先我们有一个Label textShower用于显示文本,Button textChanger作为点击的按钮

    这个问题是笔者还是一名小菜时遇到的,当时笔者是这么写的:


    public class MyFrame

    {

        Label textShower;

        Button textChanger;

        public MyFrame//实例化等省略

        {

           textChanger.setOnClickListener(new OnClickListener(){

        public void onClick(MouseEvent e){

            for(int i = 1;i <= 10;i++){

                textShower.setText(i+"");//设置文字

                Thread.sleep(1000);//等待一秒

            }

        }

        });

        }

    }

     程序的执行结果是点击后10秒没有响应,然后数值被设定为10;现在知道了,是由于AWT消息线程同时负责着图像的绘制刷新操作,而Thread.sleep属于之前的阻塞过程,导致画面停止响应。

    当时老师是这么教给我的:


    public class MyFrame

    {

        Label textShower;

        Button textChanger;

        public MyFrame//实例化等省略

        {

           textChanger.setOnClickListener(new OnClickListener(){

        public void onClick(MouseEvent e){

        new Thread(){

            public void run()

            {

                for(int i = 0;i < 10;i++){

                    textShower.setText(i+"");//设置文字

                    Thread.sleep(1000);//等待一秒

                }    

            }

        }.start();

        }

        });

        }

    }

     

    当然,这样确实能够满足题目要求,我也因此开心了一阵,不过不久我就有了新的问题:每按一次按钮产生一个线程是否合理呢?如果这样的文本组合再多几个,我也要创建更多的线程吗?要是使用者是个熊孩子来这里一通狂按这程序还受得了么....

        后来,在面向对象思想深入人心后,稍微懂面向对象的人都会知道使用抽象来简化程序,只不过在上面的问题中,我们需要抽象的不是具体的实体,而是“实际阻塞”这种抽象概念。

        在上面的代码中,笔者写的第一个onClick函数属于一个阻塞过程,其中sleep属于“实际阻塞”。

        而改版的代码中,只是使用多线程将原本的阻塞过程变为了非阻塞过程,实际上是使用了一个独立的线程将整个阻塞过程包含在内,并没有做任何的抽象。

    问题情景[1]:在这个问题中,将主要讨论实际阻塞的抽象和合理线程数量的问题。

        这个情景是不久前一位网友问我的,他的毕业设计是编写一个坦克大战的游戏,在编的差不多的时候,突然想到每一辆坦克、每一发子弹都是用单独的线程不是很合理,问我如何改进。用这个例子说明实际阻塞的抽象再合适不过了,我们先看看他写的代码片段:

    坦克类:


    public class Tank extends Thread{

        float x;//这里以横向移动为例子,只写一个属性

        float speed = 1f;

        public void run()

        {

            drawtank();//清除上一次的绘制,根据横坐标x画一个坦克

            x+=speed;

            Thread.sleep(17);//约合一秒60次

        }

    }
     

    子弹类:


    public class Bullet extends Thread{

        float x;//这里以横向移动为例子,只写一个属性

        float speed = 10f;

        public void run()

        {

            drawbullet();//清除上一次的绘制,根据横坐标x画一个子弹

            x+=speed;

            Thread.sleep(17);//约合一秒60次

        }

    }

     

      其实这样异步的绘制会使画面产生明显的抖动,而且用于同步的逻辑也十分复杂,并不是一个好的方案。

     

    其实上面两个类中的run方法中,只有sleep属于实际阻塞,也就是说是可以被抽象出来的,我们只要一个线程,每过17毫秒执行一些列非阻塞过程即可。

    上述过程中,绘制及坐标的运算属于非阻塞过程,我们将其抽象为一个接口:


    public interface Drawable

    {

        public void draw();

    }
     

    之后我们书写抽象实际阻塞的线程类:


    public class BlockThread extends Thread 

    {

        Collection<Drawable> c = new Collection<Drawable>();

        public void run()

        {

            for(Drawable d:c)

            {

                d.draw();

            }

            Thread.sleep(17);

        }

        //封装对成员c的同步CRUD不赘述

        public void addDrawable(Drawable d);

        public void removeDrawable(Drawable d);

        ...

    }
     

     

    最后,坦克和子弹的改动:
    坦克类:


    public class Tank implements Drawable{

        float x;//这里以横向移动为例子,只写一个属性

        float speed = 1f;

        @Override

        public void draw()

        {

            drawtank();//清除上一次的绘制,根据横坐标x画一个坦克

            x+=speed;

        }

    }
    子弹类:


    public class Bullet implements Drawable{

        float x;//这里以横向移动为例子,只写一个属性

        float speed = 10f;

        @Override

        public void draw()

        {

            drawbullet();//清除上一次的绘制,根据横坐标x画一个子弹

            x+=speed;

        }

    }

    我们可以发现:原有的实际阻塞过程已经被抽象到一个线程之中,而非阻塞过程,诸如绘制和坐标运算依然作为方法保留到对应类中,这样,无论有多少坦克和炮弹,只要非阻塞过程的运算压总和力不至于逼近阻塞的程度,使用一个线程即可完成所有工作。

     

        而且,如果想要添加游戏元素,例如其他类型的子弹,只需要实现Drawable接口即可。

        写到这,UI的问题也就解决了,诸如sleep这样纯粹延时的阻塞非常容易抽象,我们可以如法炮制,使用一个线程解决所有的数值延时自增的问题。但并不是所有实际阻塞都易于抽象,如socket.read(byte[] b);这样的方法显然没有抽象的余地,因此才引出后来的nio方案。

     

        最后,我们对什么时候使用多线程,以及使用线程的数量做一个总结:在编写程序时,遇到了阻塞过程而不想使整个程序停止响应时,应使用多线程;一个程序的合理线程数量取决于对实际阻塞的抽象程度。

    原文参考:https://blog.csdn.net/shuzhe66/article/details/25484195

    文章二:

    如果你的应用程序需要采取以下的操作,那么你尽可在编程的时候考虑多线程机制:

    连续的操作,需要花费忍无可忍的过长时间才可能完成
    并行计算
    为了等待网络、文件系统、用户或其他I/O响应而耗费大量的执行时间
    所以说,在动手之前,先保证自己的应用程序中是否出现了以上3种情形。

    为什么需要多线程(解释何时考虑使用线程)
    从用户的角度考虑,就是为了得到更好的系统服务;从程序自身的角度考虑,就是使目标任务能够尽可能快的完成,更有效的利用系统资源。综合考虑,一般以下场合需要使用多线程:
    1、 程序包含复杂的计算任务时
    主要是利用多线程获取更多的CPU时间(资源)。
    2、 处理速度较慢的外围设备
    比如:打印时。再比如网络程序,涉及数据包的收发,时间因素不定。使用独立的线程处理这些任务,可使程序无需专门等待结果。
    3、 程序设计自身的需要
    WINDOWS系统是基于消息循环的抢占式多任务系统,为使消息循环系统不至于阻塞,程序需要多个线程的来共同完成某些任务。

    每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。进程也可能是整个程序或者是部分程序的动态执行。线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。也可以把它理解为代码运行的上下文。所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务。通常由操作系统负责多个线程的调度和执行。

      什么是多线程?

      多线程是为了使得多个线程并行的工作以完成多项任务,以提高系统的效率。线程是在同一时间需要完成多项任务的时候被实现的。

      使用线程的好处有以下几点:

      ·使用线程可以把占据长时间的程序中的任务放到后台去处理

      ·用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度

      ·程序的运行速度可能加快

      ·在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。

      还有其他很多使用多线程的好处,这里就不一一说明了。

      一些线程模型的背景

      我们可以重点讨论一下在Win32环境中常用的一些模型。

      ·单线程模型

      在这种线程模型中,一个进程中只能有一个线程,剩下的进程必须等待当前的线程执行完。这种模型的缺点在于系统完成一个很小的任务都必须占用很长的时间。

      ·块线程模型(单线程多块模型STA)

      这种模型里,一个程序里可能会包含多个执行的线程。在这里,每个线程被分为进程里一个单独的块。每个进程可以含有多个块,可以共享多个块中的数据。程序规定了每个块中线程的执行时间。所有的请求通过Windows消息队列进行串行化,这样保证了每个时刻只能访问一个块,因而只有一个单独的进程可以在某一个时刻得到执行。这种模型比单线程模型的好处在于,可以响应同一时刻的多个用户请求的任务而不只是单个用户请求。但它的性能还不是很好,因为它使用了串行化的线程模型,任务是一个接一个得到执行的。

      ·多线程块模型(自由线程块模型)

      多线程块模型(MTA)在每个进程里只有一个块而不是多个块。这单个块控制着多个线程而不是单个线程。这里不需要消息队列,因为所有的线程都是相同的块的一个部分,并且可以共享。这样的程序比单线程模型和STA的执行速度都要块,因为降低了系统的负载,因而可以优化来减少系统idle的时间。这些应用程序一般比较复杂,因为程序员必须提供线程同步以保证线程不会并发的请求相同的资源,因而导致竞争情况的发生。这里有必要提供一个锁机制。但是这样也许会导致系统死锁的发生。

    原文参考:http://blog.sina.com.cn/s/blog_4ee24ced0101375f.html

     

    文章三:

    “IO操作的DMA(Direct Memory Access)模式”开始讲起。DMA即直接内存访问,是一种不经过CPU而直接进行内存数据存储的数据交换模式。通过DMA的数据交换几乎可以不损耗CPU的资源。在硬件中,硬盘、网卡、声卡、显卡等都有DMA功能。CLR所提供的异步编程模型就是让我们充分利用硬件的DMA功能来释放CPU的压力。

    多线程使用的主要目的在于:


    1、吞吐量:你做WEB,容器帮你做了多线程,但是他只能帮你做请求层面的。简单的说,可能就是一个请求一个线程。或多个请求一个线程。如果是单线程,那同时只能处理一个用户的请求。

    2、伸缩性:也就是说,你可以通过增加CPU核数来提升性能。如果是单线程,那程序执行到死也就利用了单核,肯定没办法通过增加CPU核数来提升性能。

    鉴于你是做WEB的,第1点可能你几乎不涉及。那这里我就讲第二点吧。

    --举个简单的例子:
    假设有个请求,这个请求服务端的处理需要执行3个很缓慢的IO操作(比如数据库查询或文件查询),那么正常的顺序可能是(括号里面代表执行时间):
    a、读取文件1  (10ms)
    b、处理1的数据(1ms)
    c、读取文件2  (10ms)
    d、处理2的数据(1ms)
    e、读取文件3  (10ms)
    f、处理3的数据(1ms)
    g、整合1、2、3的数据结果 (1ms)
    单线程总共就需要34ms。
    那如果你在这个请求内,把ab、cd、ef分别分给3个线程去做,就只需要12ms了。

    所以多线程不是没怎么用,而是,你平常要善于发现一些可优化的点。然后评估方案是否应该使用。
    假设还是上面那个相同的问题:但是每个步骤的执行时间不一样了。
    a、读取文件1  (1ms)
    b、处理1的数据(1ms)
    c、读取文件2  (1ms)
    d、处理2的数据(1ms)
    e、读取文件3  (28ms)
    f、处理3的数据(1ms)
    g、整合1、2、3的数据结果 (1ms)
    单线程总共就需要34ms。
    如果还是按上面的划分方案(上面方案和木桶原理一样,耗时取决于最慢的那个线程的执行速度),在这个例子中是第三个线程,执行29ms。那么最后这个请求耗时是30ms。比起不用单线程,就节省了4ms。但是有可能线程调度切换也要花费个1、2ms。因此,这个方案显得优势就不明显了,还带来程序复杂度提升。不太值得。

    那么现在优化的点,就不是第一个例子那样的任务分割多线程完成。而是优化文件3的读取速度。
    可能是采用缓存和减少一些重复读取。
    首先,假设有一种情况,所有用户都请求这个请求,那其实相当于所有用户都需要读取文件3。那你想想,100个人进行了这个请求,相当于你花在读取这个文件上的时间就是28×100=2800ms了。那么,如果你把文件缓存起来,那只要第一个用户的请求读取了,第二个用户不需要读取了,从内存取是很快速的,可能1ms都不到。

     

    不使用线程池的缺点

    有些开发者图省事,遇到需要多线程处理的地方,直接new Thread(...).start(),对于一般场景是没问题的,但如果是在并发请求很高的情况下,就会有些隐患:

    • 新建线程的开销。线程虽然比进程要轻量许多,但对于JVM来说,新建一个线程的代价还是挺大的,决不同于新建一个对象
    • 资源消耗量。没有一个池来限制线程的数量,会导致线程的数量直接取决于应用的并发量,这样有潜在的线程数据巨大的可能,那么资源消耗量将是巨大的
    • 稳定性。当线程数量超过系统资源所能承受的程度,稳定性就会成问题

    原文参考:https://blog.csdn.net/wujizkm/article/details/50651808

    文章四:

    在不希望等待一个耗时任务的返回结果时,会涉及到多线程,比如下载三个文件,可以在当前线程开启三个新线程分别执行,而不影响当前线程继续运行
    在spring的项目中,一个请求就是一个线程

    为什么可以多线程以及多线程有什么意义?然后你就知道自己什么时候需要用到了。

    CPU从以前的单CPU单核发展为多核、多CPU、重核等,这是多线程可以实现的基础

    多线程即意味着多个任务(子任务)可以同时执行(当然,只是宏观上),若是单线程,只能一个接一个顺序执行。
    使用多线程,最直接的目的就是希望任务完成的更快。

    当然,多线程也会产生一些不希望看到的问题

    对java的线程类Thread来进行说明:
    1:Thread是针对是java其本身所具有的,但并不能说其没有调用操作系统,其最底层的时间片调度是按照操作系统来执行的。
    Thread下可以创建Thread,
    2个Thread在一定条件下也可以相互调用。
    根据以上特点可以总结认为java中的线程能让高级程序员更好的对庞大和复杂的数据流进行拆分,重组从而减低各个环节性能需求,通过增加各项负荷达到系统资源分配的最优值

    也就是为了更快

    对于处理时间短的服务或者启动频率高的要用单线程,相反用多线程!

    展开全文
  • 到底什么时候用多线程

    万次阅读 多人点赞 2014-05-10 17:40:56
    到底什么时候用多线程? 我想大多数人在学习多线程

    到底什么时候该用多线程?

        我想大多数人在学习多线程时都会对此问题有所顾虑,尽管多线程的概念不难理解,那我们什么时候该用它呢?在大多数情况下,我们写了程序,发现有时必须使用多线程才能得到理想的运行结果,于是我们按照资料调用相关的线程类库或API改善程序,并使其正常运行;但是,到底存不存在一种判断依据,能够明确的指导我们正确地使用多线程机制来解决问题呢?笔者对此进行了一番思考,在此说说我的想法以供参考。

        在开始之前,先引入几个问题,这些问题最终都会在这篇文章里找到答案。

    问题情景[0]:设计一个简单的UI:包括一个文本标签和一个按钮,在点击按钮时文本显示由0~10的增长,每秒增长量为1。

    问题情景[1]:某同学编写的坦克大战程序中,每一个坦克和子弹均使用一个独立的线程,这是否合理?(当然不合理。。。)如果是你,你会怎么编写这个程序?

        笔者认为,多线程的使用离不开“阻塞”这个概念,不过,我想先对这个概念加以扩充,首先先来回想一下阻塞概念原本的意思,简单的说,就是程序运行到某些函数或过程后等待某些事件发生而暂时停止CPU占用的情况;也就是说,是一种CPU闲等状态,不过有时我们使用多线程并不一定是保持闲等时的程序响应,例如在追求高性能的程序中,某条线程在进行高强度的运算,此时若对运算性能不满意,我们也许会再启动若干条运算线程(当然,是在CPU有运算余力的情况下),此时,高强度运算应该归为一种“忙等”状态。

        说到这,多线程归根究底是为了解决"等"的问题,那我们这样定义一个阻塞过程程序运行该过程所消耗的时间有可能在运行上下文间产生明显的卡顿;这里使用“可能”是因为有些情况下,诸如Socket通信,如果数据源源不断的进入,那么阻塞的时间可能非常小,但我们还是使用了一条线程(nio另说)来处理它,因为我们无法保证数据到来的持续性和有效性;"卡顿"带有主观臆想,也就是说是使用者(人或一些自动化程序)不可接受的。

    接下来,对什么时候使用多线程做一个回答:编写程序过程中需要使用某些阻塞过程时,我们才使用多线程,或者更进一步讲,使用多线程的目的是对阻塞过程中的实际阻塞的抽象提取。前半句话应该很好理解,而后面的一句虽然不太好懂,不过它对一个程序应具有的合理线程数量进行了阐释(这点接下来解释)。

    好了,接下来我们回顾一些两个问题,并对它们做出解答:

    问题情景[0]

        为了方便表达,笔者在此采用伪Java代码来阐释解答过程。首先我们有一个Label textShower用于显示文本,Button textChanger作为点击的按钮

    这个问题是笔者还是一名小菜时遇到的,当时笔者是这么写的:

    public class MyFrame
    {
        Label textShower;
        Button textChanger;
        public MyFrame//实例化等省略
        {
           textChanger.setOnClickListener(new OnClickListener(){
    	public void onClick(MouseEvent e){
    		for(int i = 1;i <= 10;i++){
    			textShower.setText(i+"");//设置文字
    			Thread.sleep(1000);//等待一秒
    		}
    	}
    	});
        }
    }

        程序的执行结果是点击后10秒没有响应,然后数值被设定为10;现在知道了,是由于AWT消息线程同时负责着图像的绘制刷新操作,而Thread.sleep属于之前的阻塞过程,导致画面停止响应。

    当时老师是这么教给我的:

    public class MyFrame
    {
        Label textShower;
        Button textChanger;
        public MyFrame//实例化等省略
        {
           textChanger.setOnClickListener(new OnClickListener(){
    	public void onClick(MouseEvent e){
    	new Thread(){
    		public void run()
    		{
    			for(int i = 0;i < 10;i++){
    				textShower.setText(i+"");//设置文字
    				Thread.sleep(1000);//等待一秒
    			}	
    		}
    	}.start();
    	}
    	});
        }
    }

        当然,这样确实能够满足题目要求,我也因此开心了一阵,不过不久我就有了新的问题:每按一次按钮产生一个线程是否合理呢?如果这样的文本组合再多几个,我也要创建更多的线程吗?要是使用者是个熊孩子来这里一通狂按这程序还受得了么....

        后来,在面向对象思想深入人心后,稍微懂面向对象的人都会知道使用抽象来简化程序,只不过在上面的问题中,我们需要抽象的不是具体的实体,而是“实际阻塞”这种抽象概念。

        在上面的代码中,笔者写的第一个onClick函数属于一个阻塞过程,其中sleep属于“实际阻塞”。

        而改版的代码中,只是使用多线程将原本的阻塞过程变为了非阻塞过程,实际上是使用了一个独立的线程将整个阻塞过程包含在内,并没有做任何的抽象。

    问题情景[1]:在这个问题中,将主要讨论实际阻塞的抽象和合理线程数量的问题。

        这个情景是不久前一位网友问我的,他的毕业设计是编写一个坦克大战的游戏,在编的差不多的时候,突然想到每一辆坦克、每一发子弹都是用单独的线程不是很合理,问我如何改进。用这个例子说明实际阻塞的抽象再合适不过了,我们先看看他写的代码片段:

    坦克类:

    public class Tank extends Thread{
    	float x;//这里以横向移动为例子,只写一个属性
    	float speed = 1f;
    	public void run()
    	{
    		drawtank();//清除上一次的绘制,根据横坐标x画一个坦克
    		x+=speed;
    		Thread.sleep(17);//约合一秒60次
    	}
    }

    子弹类:

    public class Bullet extends Thread{
    	float x;//这里以横向移动为例子,只写一个属性
    	float speed = 10f;
    	public void run()
    	{
    		drawbullet();//清除上一次的绘制,根据横坐标x画一个子弹
    		x+=speed;
    		Thread.sleep(17);//约合一秒60次
    	}
    }



        其实这样异步的绘制会使画面产生明显的抖动,而且用于同步的逻辑也十分复杂,并不是一个好的方案。

    其实上面两个类中的run方法中,只有sleep属于实际阻塞,也就是说是可以被抽象出来的,我们只要一个线程,每过17毫秒执行一些列非阻塞过程即可。

    上述过程中,绘制及坐标的运算属于非阻塞过程,我们将其抽象为一个接口:

    public interface Drawable
    {
    	public void draw();
    }
    之后我们书写抽象实际阻塞的线程类:

    public class BlockThread extends Thread 
    {
    	Collection<Drawable> c = new Collection<Drawable>();
    	public void run()
    	{
    		for(Drawable d:c)
    		{
    			d.draw();
    		}
    		Thread.sleep(17);
    	}
    	//封装对成员c的同步CRUD不赘述
    	public void addDrawable(Drawable d);
    	public void removeDrawable(Drawable d);
    	...
    }
    最后,坦克和子弹的改动:
    坦克类:

    public class Tank implements Drawable{
    	float x;//这里以横向移动为例子,只写一个属性
    	float speed = 1f;
    	@Override
    	public void draw()
    	{
    		drawtank();//清除上一次的绘制,根据横坐标x画一个坦克
    		x+=speed;
    	}
    }
    子弹类:

    public class Bullet implements Drawable{
    	float x;//这里以横向移动为例子,只写一个属性
    	float speed = 10f;
    	@Override
    	public void draw()
    	{
    		drawbullet();//清除上一次的绘制,根据横坐标x画一个子弹
    		x+=speed;
    	}
    }
        我们可以发现:原有的实际阻塞过程已经被抽象到一个线程之中,而非阻塞过程,诸如绘制和坐标运算依然作为方法保留到对应类中,这样,无论有多少坦克和炮弹,只要非阻塞过程的运算压总和力不至于逼近阻塞的程度,使用一个线程即可完成所有工作。

        而且,如果想要添加游戏元素,例如其他类型的子弹,只需要实现Drawable接口即可。

        写到这,UI的问题也就解决了,诸如sleep这样纯粹延时的阻塞非常容易抽象,我们可以如法炮制,使用一个线程解决所有的数值延时自增的问题。但并不是所有实际阻塞都易于抽象,如socket.read(byte[] b);这样的方法显然没有抽象的余地,因此才引出后来的nio方案。


        最后,我们对什么时候使用多线程,以及使用线程的数量做一个总结:在编写程序时,遇到了阻塞过程而不想使整个程序停止响应时,应使用多线程;一个程序的合理线程数量取决于对实际阻塞的抽象程度。

    展开全文
  • 万字图解Java多线程

    万次阅读 多人点赞 2020-09-06 14:45:07
    前言 java多线程我个人觉得是javaSe中最难的一部分,我以前也是感觉学会了,但是真正有多线程的需求却不知道怎么下手,...什么是java多线程? 进程与线程 进程 当一个程序被运行,就开启了一个进程, 比如启动了qq,w.
  • 什么多线程?如何实现多线程

    万次阅读 多人点赞 2019-04-09 09:53:36
    【转】什么线程安全?怎么实现线程安全?什么是进程?什么线程什么线程安全?添加一个状态呢?如何确保线程安全?synchronizedlock 转自:https://blog.csdn.net/csdnnews/article/details/82321777 什么是...
  • Java多线程之线程安全问题

    千次阅读 多人点赞 2022-03-31 11:02:50
    本篇文章介绍的内容为Java多线程中的线程安全问题,此处的安全问题并不是指的像黑客入侵造成的安全问题,线程安全问题是指因多线程抢占式执行而导致程序出现bug的问题。
  • Java多线程超详解

    万次阅读 多人点赞 2019-06-11 01:00:30
    随着计算机的配置越来越高,我们需要将进程进一步优化,细分为线程,充分提高图形化界面的多线程的开发。这就要求对线程的掌握很彻底。 那么话不多说,今天本帅将记录自己线程的学习。 线程的相关API //获取当前...
  • 面试题:线程是什么?多线程

    万次阅读 多人点赞 2018-10-27 10:52:48
    什么使用多线程?多线程的示例以及解决方案?线程池是什么? 一.线程是什么? 在Thread类中有这样的明确定义:线程是程序中执行的线程,Java虚拟机允许程序同时运行多个执行线程。 怎么创建一个线程呢? Thread中...
  • 【Python 爬虫】多线程爬取

    千次阅读 2022-03-20 10:44:40
    文章目录前言一、多进程库(multiprocessing)二、多线程爬虫三、案例实操四、案例解析1、获取网页内容2、获取每一章链接3、获取每一章的正文并返回章节名和正文4、将每一章保存到本地5、多线程爬取文章 前言 简单...
  • 多线程什么跑的比单线程还要慢?!

    千次阅读 多人点赞 2019-05-30 18:18:56
    首先分配cpu资源的单位是进程。...多线程提高的是并发数量,执行的是不变的,比如现在有一个4核cpu的服务器,同一时间可执行4个线程,这样处理线程任务 的速度比较快。但是多出来的线程,5个,6个,7个,...
  • Java多线程学习(吐血超详细总结)

    万次阅读 多人点赞 2015-03-14 13:13:17
    本文主要讲了java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的一些线程函数用法、概述等。
  • 纯面试 纯文字 看起来乱但适合面试总结 多线程 什么是线程和进程?他们是什么关系? 进程:在操作系统中能够独立运行,并且作为资源分配的基本单位。...多线程什么用? 发挥多核CPU的优势 防止.
  • 什么老说python是伪多线程,怎么解决?

    万次阅读 多人点赞 2019-05-20 14:43:56
    目录一、什么多线程、多进程、守护线程1.1 进程1.2 程序1.3 线程1.4 多线程1.5 守护线程1.6 进程与线程的区别1.7 进程与线程的优缺点二、利用Python进行并行计算2.1、并行?伪并行?2.2 GIL2.2.1 GIL是什么2.3 ...
  • JAVA项目中哪些场景需要用到多线程

    千次阅读 2018-12-15 09:15:40
    这时可以用多线程,将1万条URL分成50等份,开50个线程,没个线程只需验证200条,这样所有的线程执行完是远小于1万分钟的。 场景二:需要知道一个任务的执行进度,比如我们常看到的进度条,实现...
  • 头发很多的程序员:『师父,我已经使用了多线程,为什么接口还变慢了?』 架构师:『去给我买杯咖啡,我写篇文章告诉你』 ……吭哧吭哧买咖啡去了 在实际工作中,错误使用多线程非但不能提高效率还可能使程序...
  • 多线程四大经典案例

    千次阅读 多人点赞 2022-04-11 16:32:17
    2.1阻塞队列是什么 2.2生产者消费者模型 2.3标准库中的阻塞队列 2.4阻塞队列的实现 3.定时器 3.1定时器是什么 3.2标准库中的定时器 3.3实现定时器 4.线程池 4.1什么是线程池 4.2标准库中的线程池 4.3实现...
  • Java 多线程(超详细)

    千次阅读 2021-01-12 21:14:38
    多线程学习思路:为什么学习线程?为了解决CPU利用率问题,提高CPU利用率。 =》 什么是进程?什么是线程? =》 怎么创建线程?有哪几种方式?有什么特点? =》 分别怎么启动线程? =》 多线程带来了数据安全问题,该...
  • Qt 多线程基础及线程使用方式

    千次阅读 多人点赞 2021-10-15 21:31:01
    文章目录Qt 多线程操作2.线程类QThread3.多线程使用:方式一4.多线程使用:方式二5.Qt 线程池的使用 Qt 多线程操作 应用程序在某些情况下需要处理比较复杂的逻辑, 如果只有一个线程去处理,就会导致窗口卡顿,无法...
  • java 多线程面试题及答案

    千次阅读 2021-09-18 09:20:33
    并行和并发有什么区别? 并行是指两个或者个事件在同一时刻发生;而并发是指两个或个事件在同一时间间隔发生。并行没有对 CPU 资源的抢占;并发执行的线程需要对 CPU 资源进行抢占。 并行执行的线程之间不存在...
  • Java多线程面试题(面试必备)

    万次阅读 多人点赞 2020-05-26 01:15:38
    并发编程1.1 并发编程的优缺点1.2 并发编程的三要素1.3 并发和并行有和区别1.4 什么多线程多线程的优劣?2. 线程与进程2.1 什么是线程与进程2.2 线程与进程的区别2.3 用户线程与守护线程2.4 什么是线程死锁2.5 ...
  • 爬虫 第五讲 多线程爬虫

    万次阅读 2021-04-29 15:30:00
    爬虫 第五讲 多线程爬虫 一、多线程 1.多线程基本介绍 有很多的场景中的事情是同时进行的,比如开车的时候 手和脚共同来驾驶汽车,再比如唱歌跳舞也是同时进行的。 程序中模拟多任务 import time def sing(): for ...
  • 多线程常见的面试题

    万次阅读 2020-09-16 16:21:58
    多线程常见的面试题: 1. 什么是线程和进程? 线程与进程的关系,区别及优缺点? 进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。 ...
  • 多线程线程数设置多少合适

    万次阅读 多人点赞 2020-06-30 01:15:04
    前沿 大家都过线程池,但是线程池数量设置为多少比较合理呢? 线程数的设置的最主要的目的是为了充分并合理地...温故为什么使用线程 场景 如果有两个任务需要处理,一个任务A,一个任务B 方案一:一个线程执行任务
  • Linux: 多线程

    千次阅读 2021-11-29 10:42:49
    在linux之前学习进程的时候 ,进程就是一个pcb, 但是在现在学习线程时候, 发现线程是进程中的一条执行流,而因为linux下执行流是通过pcb来完成的,所以理解pcb是linux下的执行流,反推得到了一个结论,linux下的一...
  • 如果你的硬件跟不上,只有一个cpu,那么多线程从并发变成了串行了,另外再加上线程上下文切换的时候,那你就得不偿失了.2.原子问题如果多线程是同步操作一个原子数据,(多个线程同步去处理一个加锁的对象),那效率.....
  • Redis是目前广为人知的一个内存数据库,在各个场景中都有着非常丰富的应用,...所以,在Redis 6.0 推出之后,我想去了解下为什么采用多线程,现在采用的多线程和以前版本有什么区别?为什么这么晚才使用多线程? Redis
  • 多线程的几种实现方式

    千次阅读 2020-08-02 18:08:57
    1.使用实现多线程有四种方式:①继承Thread类;②实现Runnable接口;③使用Callable和FutureTask实现有返回值的多线程;④使用ExecutorService和Executors工具类实现线程池(如果需要线程的返回值,需要在线程中实现...
  • 【java多线程编程】三种多线程的实现方式

    万次阅读 多人点赞 2019-01-01 16:20:56
    文章目录前言进程与线程继承Thread类,实现多线程FAQ 为什么多线程的启动不直接使用run()方法而必须使用Thread类中start()方法呢?基于Runnable接口实现多线程Thread 与 Runnable 的关系Callable实现多线程线程...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 552,807
精华内容 221,122
关键字:

多线程什么时候用得到