java深入理解多线程weixin_42229272ZIP深入简出多线程.zip 526.34KB 立即下载资源文件列表:ZIP 深入简出多线程.zip 大约有1个文件 深入简出多线程.pdf 588.32KB 资源介绍: Java多线程是并发编程中的一个重要概念,它允许程序在同一时刻执行多个任务。以下是对Java多线程的深入理解: 线程概述 基本概念:线程是操作系统能够进行运算调度的最小单位,一个进程可以包含多个线程。 特性:线程不拥有系统资源,只拥有一点必不可少的、能保证独立运行的资源。同一进程中的线程共享该进程的资源,但各自拥有独立的堆栈和局部变量。 线程创建与启动 创建方式:在Java中,可以通过继承Thread类或实现Runnable接口来创建线程。 启动方法:通过调用线程对象的start()方法来启动线程,这将导致run()方法被调用。 线程状态 线程在其生命周期中会经历新建态、就绪态、运行态、阻塞/等待/超时等待和死亡态等状态。 线程同步 同步问题:在多线程环境中,当多个线程访问共享资源时,可能会出现数据不一致和竞态条件等问题。 解决方法:使用synchronized关键字或锁机制(如ReentrantLock)来确保同一时间只有一个线程可以访问被同步的代码。 线程通信 Object类中的wait()、notify()和notifyAll()方法提供了一种线程间的通信方式。 高级 <link href="/image.php?url=https://csdnimg.cn/release/download_crawler_static/css/base.min.css" rel="stylesheet"/><link href="/image.php?url=https://csdnimg.cn/release/download_crawler_static/css/fancy.min.css" rel="stylesheet"/><link href="/image.php?url=https://csdnimg.cn/release/download_crawler_static/90017054/2/raw.css" rel="stylesheet"/><div id="sidebar" style="display: none"><div id="outline"></div></div><div class="pf w0 h0" data-page-no="1" id="pf1"><div class="pc pc1 w0 h0"><img alt="" class="bi x0 y0 w1 h1" src="/image.php?url=https://csdnimg.cn/release/download_crawler_static/90017054/bg1.jpg"/><div class="c x1 y1 w2 h2"><div class="t m0 x2 h3 y2 ff1 fs0 fc0 sc0 ls0 ws0">小牛和同学开发的八股文网站<span class="ff2">http://interviewtop.top </span>持续更新<span class="ff2">BA<span class="_ _0"></span>T<span class="ff1">面试题。</span></span></div><div class="t m0 x2 h4 y3 ff3 fs1 fc1 sc0 ls0 ws0">简述<span class="ff4">java</span>内存模型(<span class="ff4">JMM</span>)</div><div class="t m0 x2 h3 y4 ff2 fs0 fc0 sc0 ls0 ws0">java<span class="ff1">内存模型定义了程序中各种变量的访问规则。其规定所有变量都存储在主内存,线程均有自己的工</span></div><div class="t m0 x2 h3 y5 ff1 fs0 fc0 sc0 ls0 ws0">作内存。</div><div class="t m0 x2 h3 y6 ff1 fs0 fc0 sc0 ls0 ws0">工作内存中保存被该线程使用的变量的主内存副本,线程对变量的所有操作都必须在工作空间进行,不</div><div class="t m0 x2 h3 y7 ff1 fs0 fc0 sc0 ls0 ws0">能直接读写主内存数据。操作完成后,线程的工作内存通过缓存一致性协议将操作完的数据刷回主存。</div><div class="t m0 x2 h4 y8 ff3 fs1 fc1 sc0 ls0 ws0">简述<span class="ff4">as-if-serial</span></div><div class="t m0 x2 h3 y9 ff1 fs0 fc0 sc0 ls0 ws0">编译器等会对原始的程序进行指令重排序和优化。但不管怎么重排序,其结果和用户原始程序输出预定</div><div class="t m0 x2 h3 ya ff1 fs0 fc0 sc0 ls0 ws0">结果一致。</div><div class="t m0 x2 h4 yb ff3 fs1 fc1 sc0 ls0 ws0">简述<span class="ff4">happens-before</span>八大原则</div><div class="t m0 x2 h3 yc ff1 fs0 fc0 sc0 ls0 ws0">程序次序规则:一个线程内写在前面的操作先行发生于后面的。</div><div class="t m0 x2 h3 yd ff1 fs0 fc0 sc0 ls0 ws0">锁定规则:<span class="ff2"> unlock </span>操作先行发生于后面对同一个锁的<span class="ff2"> lock </span>操作。</div><div class="t m0 x2 h3 ye ff2 fs0 fc0 sc0 ls0 ws0">volatile <span class="ff1">规则:对</span> volatile <span class="ff1">变量的写操作先行发生于后面的读操作。</span></div><div class="t m0 x2 h3 yf ff1 fs0 fc0 sc0 ls0 ws0">线程启动规则:线程的<span class="ff2"> start </span>方法先行发生于线程的每个动作。</div></div></div><div class="pi" data-data='{"ctm":[1.568627,0.000000,0.000000,1.568627,0.000000,0.000000]}'></div></div><div id="pf2" class="pf w0 h0" data-page-no="2"><div class="pc pc2 w0 h0"><img class="bi x0 y0 w1 h1" alt="" src="/image.php?url=https://csdnimg.cn/release/download_crawler_static/90017054/bg2.jpg"><div class="c x1 y10 w2 h2"><div class="t m0 x2 h3 y11 ff1 fs0 fc0 sc0 ls0 ws0">线程中断规则:对线程<span class="ff2">interrupt()</span>方法的调用先行发生于被中断线程的代码检测到中断事件的发生。</div><div class="t m0 x2 h3 y12 ff1 fs0 fc0 sc0 ls0 ws0">线程终止规则:线程中所有操作先行发生于对线程的终止检测。</div><div class="t m0 x2 h3 y13 ff1 fs0 fc0 sc0 ls0 ws0">对象终结规则:对象的初始化先行发生于<span class="ff2"> finalize </span>方法。</div><div class="t m0 x2 h3 y14 ff1 fs0 fc0 sc0 ls0 ws0">传递性规则:如果操作<span class="ff2"> A </span>先行发生于操作<span class="ff2"> B</span>,操作<span class="ff2"> B </span>先行发生于操作<span class="ff2"> C</span>,那么操作<span class="ff2"> A </span>先行发生于操作</div><div class="t m0 x2 h5 y15 ff2 fs0 fc0 sc0 ls0 ws0">C</div><div class="t m0 x2 h4 y16 ff4 fs1 fc1 sc0 ls0 ws0">as-if-serial <span class="ff3">和</span> happens-before <span class="ff3">的区别</span></div><div class="t m0 x2 h3 y17 ff2 fs0 fc0 sc0 ls0 ws0">as-if-serial <span class="ff1">保证单线程程序的执行结果不变,</span>happens-before <span class="ff1">保证正确同步的多线程程序的执行结果不</span></div><div class="t m0 x2 h3 y18 ff1 fs0 fc0 sc0 ls0 ws0">变。</div><div class="t m0 x2 h4 y19 ff3 fs1 fc1 sc0 ls0 ws0">简述原子性操作</div><div class="t m0 x2 h3 y1a ff1 fs0 fc0 sc0 ls0 ws0">一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行,这就是</div><div class="t m0 x2 h3 y1b ff1 fs0 fc0 sc0 ls0 ws0">原子性操作。</div><div class="t m0 x2 h4 y1c ff3 fs1 fc1 sc0 ls0 ws0">简述线程的可见性</div><div class="t m0 x2 h3 y1d ff1 fs0 fc0 sc0 ls0 ws0">可见性指当一个线程修改了共享变量时,其他线程能够立即得知修改。<span class="ff2">volatile,synchronized,final</span>都能</div><div class="t m0 x2 h3 y1e ff1 fs0 fc0 sc0 ls0 ws0">保证可见性。</div><div class="t m0 x2 h4 y1f ff3 fs1 fc1 sc0 ls0 ws0">简述有序性</div><div class="t m0 x2 h3 y20 ff1 fs0 fc0 sc0 ls0 ws0">即虽然多线程存在并发和指令优化等操作,在本线程内观察该线程的所有执行操作是有序的。</div><div class="t m0 x2 h4 y21 ff3 fs1 fc1 sc0 ls0 ws0">简述<span class="ff4">java</span>中<span class="ff4">volatile</span>关键字作用</div><div class="t m0 x3 h3 y22 ff2 fs0 fc0 sc0 ls0 ws0">1<span class="_ _0"></span>. <span class="_ _1"></span><span class="ff1">保证变量对所有线程的可见性。</span></div><div class="t m0 x4 h3 y23 ff1 fs0 fc0 sc0 ls0 ws0">当一条线程修改了变量值,新值对于其他线程来说是立即可以得知的。</div><div class="t m0 x3 h3 y24 ff2 fs0 fc0 sc0 ls0 ws0">2<span class="_ _0"></span>. <span class="_ _1"></span><span class="ff1">禁止指令重排序优化。使用</span> volatile <span class="ff1">变量进行写操作,汇编指令带有</span> lock <span class="ff1">前缀,相当于一个内存屏</span></div><div class="t m0 x4 h3 y25 ff1 fs0 fc0 sc0 ls0 ws0">障,编译器不会将后面的指令重排到内存屏障之前。</div><div class="t m0 x2 h4 y26 ff4 fs1 fc1 sc0 ls0 ws0">java<span class="ff3">线程的实现方式</span></div></div></div><div class="pi" data-data='{"ctm":[1.568627,0.000000,0.000000,1.568627,0.000000,0.000000]}'></div></div><div id="pf3" class="pf w0 h0" data-page-no="3"><div class="pc pc3 w0 h0"><img class="bi x0 y0 w1 h1" alt="" src="/image.php?url=https://csdnimg.cn/release/download_crawler_static/90017054/bg3.jpg"><div class="c x1 y27 w2 h6"><div class="t m0 x3 h3 y28 ff2 fs0 fc0 sc0 ls0 ws0">1<span class="_ _0"></span>. <span class="_ _1"></span><span class="ff1">实现</span>Runnable<span class="ff1">接口</span></div><div class="t m0 x3 h3 y29 ff2 fs0 fc0 sc0 ls0 ws0">2<span class="_ _0"></span>. <span class="_ _1"></span><span class="ff1">继承</span>Thread<span class="ff1">类。</span></div><div class="t m0 x3 h3 y2a ff2 fs0 fc0 sc0 ls0 ws0">3<span class="_ _0"></span>. <span class="_ _1"></span><span class="ff1">实现</span>Callable<span class="ff1">接口</span></div><div class="t m0 x2 h4 y2b ff3 fs1 fc1 sc0 ls0 ws0">简述<span class="ff4">java</span>线程的状态</div><div class="t m0 x2 h3 y2c ff1 fs0 fc0 sc0 ls0 ws0">线程状态有<span class="ff2">New<span class="_ _0"></span>, RUNNABLE, BLOCK, WAITING, TIMED_W<span class="_ _0"></span>AITING, THERMINA<span class="_ _0"></span>TED </span></div><div class="t m0 x2 h3 y2d ff2 fs0 fc0 sc0 ls0 ws0">NEW<span class="ff1">:新建状态,线程被创建且未启动,此时还未调用</span> start <span class="ff1">方法。</span></div><div class="t m0 x2 h3 y2e ff2 fs0 fc0 sc0 ls0 ws0">RUNNABLE: <span class="ff1">运行状态。其表示线程正在</span>JVM<span class="ff1">中执行,但是这个执行,不一定真的在跑,也可能在排队</span></div><div class="t m0 x2 h3 y2f ff1 fs0 fc0 sc0 ls0 ws0">等<span class="ff2">CPU</span>。</div><div class="t m0 x2 h3 y30 ff2 fs0 fc0 sc0 ls0 ws0">BLOCKED<span class="ff1">:阻塞状态。线程等待获取锁,锁还没获得。</span></div><div class="t m0 x2 h3 y31 ff2 fs0 fc0 sc0 ls0 ws0">W<span class="_ _2"></span>AITING: <span class="ff1">等待状态。线程内</span>run<span class="ff1">方法运行完语句</span>Object.wait()/Thread.join()<span class="ff1">进入该状态。</span></div><div class="t m0 x2 h3 y32 ff2 fs0 fc0 sc0 ls0 ws0">TIMED_W<span class="_ _2"></span>AITING<span class="ff1">:限期等待。在一定时间之后跳出状态。调用</span>Thread.sleep(long) Object.wait(long)</div><div class="t m0 x2 h3 y33 ff2 fs0 fc0 sc0 ls0 ws0">Thread.join(long)<span class="ff1">进入状态。其中这些参数代表等待的时间。</span></div><div class="t m0 x2 h3 y34 ff2 fs0 fc0 sc0 ls0 ws0">TERMINA<span class="_ _0"></span>TED<span class="ff1">:结束状态。线程调用完</span>run<span class="ff1">方法进入该状态。</span></div><div class="t m0 x2 h4 y35 ff3 fs1 fc1 sc0 ls0 ws0">简述线程通信的方式</div><div class="t m0 x3 h3 y36 ff2 fs0 fc0 sc0 ls0 ws0">1<span class="_ _0"></span>. <span class="_ _1"></span>volatile <span class="ff1">关键词修饰变量,保证所有线程对变量访问的可见性。</span></div><div class="t m0 x3 h3 y37 ff2 fs0 fc0 sc0 ls0 ws0">2<span class="_ _0"></span>. <span class="_ _1"></span>synchronized<span class="ff1">关键词。确保多个线程在同一时刻只能有一个处于方法或同步块中。</span></div><div class="t m0 x3 h3 y38 ff2 fs0 fc0 sc0 ls0 ws0">3<span class="_ _0"></span>. <span class="_ _1"></span>wait/notify<span class="ff1">方法</span></div><div class="t m0 x3 h3 y39 ff2 fs0 fc0 sc0 ls0 ws0">4<span class="_ _0"></span>. <span class="_ _1"></span>IO<span class="ff1">通信</span></div><div class="t m0 x2 h4 y3a ff3 fs1 fc1 sc0 ls0 ws0">简述线程池</div><div class="t m0 x2 h3 y3b ff1 fs0 fc0 sc0 ls0 ws0">没有线程池的情况下,多次创建,销毁线程开销比较大。如果在开辟的线程执行完当前任务后执行接下</div><div class="t m0 x2 h3 y3c ff1 fs0 fc0 sc0 ls0 ws0">来任务,复用已创建的线程,降低开销、控制最大并发数。</div><div class="t m0 x2 h3 y3d ff1 fs0 fc0 sc0 ls0 ws0">线程池创建线程时,会将线程封装成工作线程<span class="ff2"> Worker</span>,<span class="ff2">W<span class="_ _2"></span>orker <span class="ff1">在执行完任务后还会循环获取工作队列</span></span></div><div class="t m0 x2 h3 y3e ff1 fs0 fc0 sc0 ls0 ws0">中的任务来执行。</div><div class="t m0 x2 h3 y3f ff1 fs0 fc0 sc0 ls0 ws0">将任务派发给线程池时,会出现以下几种情况</div><div class="t m0 x3 h3 y40 ff2 fs0 fc0 sc0 ls0 ws0">1<span class="_ _0"></span>. <span class="_ _1"></span><span class="ff1">核心线程池未满,创建一个新的线程执行任务。</span></div><div class="t m0 x3 h3 y41 ff2 fs0 fc0 sc0 ls0 ws0">2<span class="_ _0"></span>. <span class="_ _1"></span><span class="ff1">如果核心线程池已满,工作队列未满,将线程存储在工作队列。</span></div></div></div><div class="pi" data-data='{"ctm":[1.568627,0.000000,0.000000,1.568627,0.000000,0.000000]}'></div></div><div id="pf4" class="pf w0 h0" data-page-no="4"><div class="pc pc4 w0 h0"><img class="bi x0 y0 w1 h1" alt="" src="/image.php?url=https://csdnimg.cn/release/download_crawler_static/90017054/bg4.jpg"><div class="c x1 y42 w2 h7"><div class="t m0 x3 h3 y43 ff2 fs0 fc0 sc0 ls0 ws0">3<span class="_ _0"></span>. <span class="_ _1"></span><span class="ff1">如果工作队列已满,线程数小于最大线程数就创建一个新线程处理任务。</span></div><div class="t m0 x3 h3 y44 ff2 fs0 fc0 sc0 ls0 ws0">4<span class="_ _0"></span>. <span class="_ _1"></span><span class="ff1">如果超过大小线程数,按照拒绝策略来处理任务。</span></div><div class="t m0 x2 h4 y45 ff3 fs1 fc1 sc0 ls0 ws0">线程池参数</div><div class="t m0 x3 h3 y46 ff2 fs0 fc0 sc0 ls0 ws0">1<span class="_ _0"></span>. <span class="_ _1"></span>corePoolSize<span class="ff1">:常驻核心线程数。超过该值后如果线程空闲会被销毁。</span></div><div class="t m0 x3 h3 y47 ff2 fs0 fc0 sc0 ls0 ws0">2<span class="_ _0"></span>. <span class="_ _1"></span>maximumPoolSize<span class="ff1">:线程池能够容纳同时执行的线程最大数。</span></div><div class="t m0 x3 h3 y48 ff2 fs0 fc0 sc0 ls0 ws0">3<span class="_ _0"></span>. <span class="_ _1"></span>keepAliveT<span class="_ _2"></span>ime<span class="ff1">:线程空闲时间,线程空闲时间达到该值后会被销毁,直到只剩下</span> corePoolSize <span class="ff1">个</span></div><div class="t m0 x4 h3 y49 ff1 fs0 fc0 sc0 ls0 ws0">线程为止,避免浪费内存资源。</div><div class="t m0 x3 h3 y4a ff2 fs0 fc0 sc0 ls0 ws0">4<span class="_ _0"></span>. <span class="_ _1"></span>workQueue<span class="ff1">:工作队列。</span></div><div class="t m0 x3 h3 y4b ff2 fs0 fc0 sc0 ls0 ws0">5<span class="_ _0"></span>. <span class="_ _1"></span>threadFactory<span class="ff1">:线程工厂,用来生产一组相同任务的线程。</span></div><div class="t m0 x3 h3 y4c ff2 fs0 fc0 sc0 ls0 ws0">6<span class="_ _0"></span>. <span class="_ _1"></span>handler<span class="ff1">:拒绝策略。有以下几种拒绝策略:</span></div><div class="t m0 x4 h3 y4d ff2 fs0 fc0 sc0 ls0 ws0">AbortPolicy<span class="ff1">:丢弃任务并抛出异常</span></div><div class="t m0 x4 h3 y4e ff2 fs0 fc0 sc0 ls0 ws0">CallerRunsPolicy<span class="ff1">:</span> <span class="ff1">重新尝试提交该任务</span></div><div class="t m0 x4 h3 y4f ff2 fs0 fc0 sc0 ls0 ws0">DiscardOldestPolicy <span class="ff1">抛弃队列里等待最久的任务并把当前任务加入队列</span></div><div class="t m0 x4 h3 y50 ff2 fs0 fc0 sc0 ls0 ws0">DiscardPolicy <span class="ff1">表示直接抛弃当前任务但不抛出异常。</span></div><div class="t m0 x2 h4 y51 ff3 fs1 fc1 sc0 ls0 ws0">线程池创建方法</div><div class="t m0 x3 h3 y52 ff2 fs0 fc0 sc0 ls0 ws0">1<span class="_ _0"></span>. <span class="_ _1"></span>newFixedThreadPool<span class="ff1">,创建固定大小的线程池。</span></div><div class="t m0 x3 h3 y53 ff2 fs0 fc0 sc0 ls0 ws0">2<span class="_ _0"></span>. <span class="_ _1"></span>newSingleThreadExecutor<span class="ff1">,使用单线程线程池。</span></div><div class="t m0 x3 h3 y54 ff2 fs0 fc0 sc0 ls0 ws0">3<span class="_ _0"></span>. <span class="_ _1"></span>newCachedThreadPool<span class="ff1">,</span>maximumPoolSize <span class="ff1">设置为</span> Integer <span class="ff1">最大值,工作完成后会回收工作线程</span></div><div class="t m0 x3 h3 y55 ff2 fs0 fc0 sc0 ls0 ws0">4<span class="_ _0"></span>. <span class="_ _1"></span>newScheduledThreadPool<span class="ff1">:支持定期及周期性任务执行,不回收工作线程。</span></div><div class="t m0 x3 h3 y56 ff2 fs0 fc0 sc0 ls0 ws0">5<span class="_ _0"></span>. <span class="_ _1"></span>newWorkStealingPool<span class="ff1">:一个拥有多个任务队列的线程池。</span></div><div class="t m0 x2 h4 y57 ff3 fs1 fc1 sc0 ls0 ws0">简述<span class="ff4">Executor</span>框架</div><div class="t m0 x2 h3 y58 ff2 fs0 fc0 sc0 ls0 ws0">Executor<span class="ff1">框架目的是将任务提交和任务如何运行分离开来的机制。用户不再需要从代码层考虑设计任务</span></div><div class="t m0 x2 h3 y59 ff1 fs0 fc0 sc0 ls0 ws0">的提交运行,只需要调用<span class="ff2">Executor</span>框架实现类的<span class="ff2">Execute</span>方法就可以提交任务。产生线程池的函数</div><div class="t m0 x2 h3 y5a ff2 fs0 fc0 sc0 ls0 ws0">ThreadPoolExecutor<span class="ff1">也是</span>Executor<span class="ff1">的具体实现类。</span></div><div class="t m0 x2 h4 y5b ff3 fs1 fc1 sc0 ls0 ws0">简述<span class="ff4">Executor</span>的继承关系</div><div class="t m0 x4 h3 y5c ff2 fs0 fc0 sc0 ls0 ws0">Executor<span class="ff1">:一个接口,其定义了一个接收</span>Runnable<span class="ff1">对象的方法</span>executor<span class="ff1">,该方法接收一个</span>Runable</div><div class="t m0 x4 h3 y5d ff1 fs0 fc0 sc0 ls0 ws0">实例执行这个任务。</div></div></div><div class="pi" data-data='{"ctm":[1.568627,0.000000,0.000000,1.568627,0.000000,0.000000]}'></div></div>