0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

软件大师开小灶:线程和线程池

Linux阅码场 来源:未知 作者:胡薇 2018-05-18 11:06 次阅读

大师,最近我在学习线程,有很多迷惑的地方。

说来听听,让为师给你排解一下。

第一个问题问题就是为什么要多线程啊, 我看了操作系统中的多进程管理,不是挺好的吗? 多线程似乎没有必要啊!

不错,多问问为什么,总是有好处的。所谓线程,就是程序代码的执行,一个进程至少得有一个线程,要不然,这个进程怎么运行? 对吧?

这个我理解。

以你常用的Word为例,假设这个进程没有多线程(或者说它只有一个线程), 如果它有个定时保存文档的功能,你想象下,当这个自动保存的功能在运行的时候,你还能继续输入文字吗?

不能

对,这就是问题所在了,单线程只能干一件事情,无法并发和并行。直接导致用户体验不好。CPU快速的运算能力,还有多核,就被浪费了。

那我完全可以用多进程来处理啊, 一个进程来接受用户输入文字,另外一个进程来自动保存。

是可以这么做,但进程是个重量级的家伙,并且进程之间是隔离的,他们要想共享数据,例如被编辑的文件内容,那是非常麻烦的。

原来如此。

古人云:进程是拥有资源的基本单位, 线程是CPU调度的基本单位,这句话你理解吗?

不是特别明白......

举个例子,有两个进程,一个是Word, 一个是QQ音乐。 Word 进程打开了文件,这是它的资源,QQ音乐打开了Socket,这也是它的资源。

假设Word有两个线程:T1负责接受用户的文字输入,T2 负责自动保存。

QQ音乐也有两个线程:T3负责从Socket中读取数据,T4负责对音乐数据进行解码。

操作系统在做调度的时候,基本单位不是Word,QQ音乐这样的进程,而是T1, T2,T3,T4这些线程。明白了吗?

(点头)原来每个线程执行的都是进程代码的某个片段啊! 对了,我听师兄们在讨论什么Java多线程编程,说是很复杂,但是他们从来没提到过Java 多进程编程,这是怎么回事啊?

不错,你的师兄们都没有想到这个问题,看来你已经开始思考了。我先问你,你写的Java程序是不是运行在JVM中? 对操作系统来说,JVM是个什么东西?

嗯... JVM其实就是java.exe运行起来,那它肯定是个进程了。

那在一个进程中还能进行多进程编程吗?

(恍然大悟)奥,那是肯定不行了,Java程序运行在JVM当中, JVM这个进程其实就是他们的容器。 我听说Python, Ruby 等动态语言也都有虚拟机, 这么说他们也可以进行多线程编程了。

是啊,虚拟机是个好东西,你们真是遇上了好时候啊, 不用再费劲心机去操作内存。这虚拟机还能屏蔽操作系统的差异,你写的程序可以在任意的支持该语言虚拟机的操作系统中运行。 可移植性很重要,要不然,你在Mac/Windows上开发的程序怎么能不加修改地放到Linux上去运行呢?

我在Java 中创建了一个Thread对象,为什么要调用start方法才能启动线程? 为什么不能直接调用run方法呢?

你要是直接调用run()方法,会是什么效果?

就是用当前线程去执行一个普通函数而已,根本没有什么新线程创建出来。

这就对了,你想创建一个新的线程出来,肯定得有准备工作啊,设置好这个线程的上下文,比如这个线程的栈(用于函数调用),线程的状态,这个线程的PC(Program Counter)等等一系列信息以后,这个线程才可以被调度, 一旦被调度,就会执行那个run()方法了

明白了大师,还有一个问题,既然线程是属于进程的,可以共享进程的资源, 那创建一个线程应该很轻松啊,为什么要有线程池这个东西呢?

虽然线程是个轻量级的东西, 但是对于互联网应用来说,如果每个用户的请求都创建一个线程,那会非常得多,服务器也是难于承受, 再说了,众多的线程去竞争CPU,不断切换,也会让CPU调度不堪重负,很多线程将不得不等待。所以前辈们的思路就是(1)用少量的线程 (2) 让线程保持忙碌

奥,就是说只创建一定数量的线程,让这些线程去处理所有的任务,任务执行完了以后,线程并不结束,而是回到线程池中去,等待接受下一个任务。

这些线程可以预先创建,任务来了就不用临时再创建了,立刻开始服务。

预先创建? 您刚才不是说线程是程序代码的执行吗? 它是个动态的东西,怎么可能预先创建? 如果真的创建起来了,就会调用run方法, 马上执行完了, 线程就结束了!

你忘了重要的一点,线程的状态。当线程池的线程刚创建时,让他们进入阻塞状态:等待某个任务的到来。 如果任务来了,那就好办,唤醒其中一个线程,让它拿到任务去执行即可。

可是怎么让他们进入阻塞状态?

看来之前的图我白画了, BlockingQueue听说过没有? 没听说过? 其实很简单,就是一个线程调用它的take()方法取数据时, 如果这个Queue中没有数据,该线程会阻塞;同样,一个线程调用它的put方法放数据时,如果Queue满了, 也会阻塞。

奥,看来线程池中每个线程的run()方法中,要设置一个循环,每次都尝试从BlockingQueue中获取任务,如果Queue是空的,就阻塞等待, 如果有任务来了,就会通知到线程池的某一个线程去处理,处理完了以后,依然试图从BlockingQueue中获取任务,就这么依次循环下去。

线程池中的Worker线程:public class WorkerThread extends Thread { private BlockingQueue taskQueue = null; private boolean isStopped = false; //持有一个BlockingQueue的实例 public WorkerThread(BlockingQueue queue){ taskQueue = queue; } public void run(){ while(!isStopped()){ try{ Task task = taskQueue.take(); task.execute(); } catch(Exception e){ //log or otherwise report exception, //but keep pool thread alive. } } } ......略......}

没错,你这个代码是一种简单的实现,我的老朋友Doug Lea大师写了一套非常好的实现,已经被吸收进JDK了,作为java.util.concurrent包的一部分,你直接调用即可,不用自己动手了。

ExecutorService executorService = Executors.newFixedThreadPool(10);executorService.execute(new Runnable() { public void run() { System.out.println("Asynchronous task"); }});executorService.shutdown();

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 线程池
    +关注

    关注

    0

    文章

    53

    浏览量

    6771
  • 线程
    +关注

    关注

    0

    文章

    491

    浏览量

    19508

原文标题:小白科普:线程和线程池

文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    线程管理之线程切换

    线程管理之线程切换前言基本信息前言说明PendSV_Handler函数前言基本信息名称描述说明RT-Thread Studio 软件版本版本: 1.1.3RT-Thread 系统版本
    发表于 08-24 08:19

    线程是如何实现的

    线程的概念是什么?线程是如何实现的?
    发表于 02-28 06:20

    线程创建的两种方法

    1. 使用内置模块在使用多线程处理任务时也不是线程越多越好,由于在切换线程的时候,需要切换上下文环境,依然会造成cpu的大量开销。为解决这个问题,线程
    发表于 03-16 16:15

    线程好还是单线程好?单线程和多线程的区别 优缺点分析

    摘要:如今单线程与多线程已经得到普遍运用,那么到底多线程好还是单线程好呢?单线程和多线程的区别又
    发表于 12-08 09:33 8w次阅读

    线程的实现方式,四线程和八线程的区别介绍

    摘要:线程是程序执行流的最小单元。四线程和八线程线程的两种表现形式,下面来看看它们之间的区别以及线程的实现方式。
    发表于 12-08 14:31 1.1w次阅读

    德国汽车企业政府协助 台媒:“开小灶”行为已违反自由市场机制

    指出,此种“开小灶”的行为已违反自由市场机制。 digitimes报道指出,面对德国政府的要求,中国台湾地区经济部长王美花已邀请包括台积电、联电、世界先进、环球晶在内的四大晶圆代工厂开会,研讨如何增产车用芯片,然而此举引来了半导体业界不
    的头像 发表于 01-29 10:09 1212次阅读

    处理器6核12线程和8核16线程区别大吗

    很多网友问处理器6核12线程和8核16线程的区别是什么,首先我们来了解下什么是6核12线程和8核16线程
    发表于 01-01 17:44 5.2w次阅读

    MFC多线程线程同步

    MFC中有两类线程,分别称之为工作者线程和用户界面线程。二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环。
    发表于 06-01 17:03 0次下载

    什么是线程线程池中线程实现复用的原理

    一般建议自定义线程工厂,构建线程的时候设置线程的名称,这样就在查日志的时候就方便知道是哪个线程执行的代码。
    发表于 01-29 13:44 1349次阅读

    线程线程

    线程池通常用于服务器应用程序。 每个传入请求都将分配给线程池中的一个线程,因此可以异步处理请求,而不会占用主线程,也不会延迟后续请求的处理
    的头像 发表于 02-28 09:53 471次阅读
    多<b class='flag-5'>线程</b>之<b class='flag-5'>线程</b>池

    什么是线程安全?如何理解线程安全?

    在多线程编程中,线程安全是必须要考虑的因素。
    的头像 发表于 05-30 14:33 1528次阅读
    什么是<b class='flag-5'>线程</b>安全?如何理解<b class='flag-5'>线程</b>安全?

    核心线程数和最大线程数区别

    核心线程数和最大线程数区别 核心线程数是线程池中一直存在的线程数,不会被回收。最大线程数是
    的头像 发表于 06-01 09:33 6148次阅读

    线程池的线程怎么释放

    线程分组看,pool名开头线程占616条,而且waiting状态也是616条,这个点就非常可疑了,我断定就是这个pool开头线程池导致的问题。我们先排查为何这个线程池中会有600+的
    发表于 07-31 10:49 1278次阅读
    <b class='flag-5'>线程</b>池的<b class='flag-5'>线程</b>怎么释放

    线程idm下载软件

    线程idm下载软件
    发表于 10-23 09:23 0次下载

    核心线程数和最大线程数怎么设置

    核心线程数和最大线程数是Java线程池中重要的参数,用来控制线程池中线程的数量和行为。正确地设置这两个参数可以优化系统的性能和资源利用率。本
    的头像 发表于 12-01 13:50 4201次阅读