ImageVerifierCode 换一换
格式:DOCX , 页数:15 ,大小:83.71KB ,
资源ID:17055579      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/17055579.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Java线程池基础详解Word格式文档下载.docx)为本站会员(b****3)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Java线程池基础详解Word格式文档下载.docx

1、二、Executor框架Executor框架在Java1.5中引入,大部分的类都在包java.util.concurrent中,由大神Doug Lea写成,其中常用到的有以下几个类和接口:1. java.util.concurrent.Executor一个只包含一个方法的接口,它的抽象含义是:用来执行一个Runnable任务的执行器。2. java.util.concurrent.ExecutorService对Executor的一个扩展,增加了很多对于任务和执行器的生命周期进行管理的接口,也是通常进行多线程开发最常使用的接口。3. java.util.concurrent.ThreadFac

2、tory一个生成新线程的接口。用户可以通过实现这个接口管理对线程池中生成线程的逻辑4. java.util.concurrent.Executors提供了很多不同的生成执行器的实用方法,比如基于线程池的执行器的实现。三、为什么要用线程池Java从最开始就是基于线程的,线程在Java里被封装成一个类java.lang.Thread。在面试中很多面试官都会问一个很基础的关于线程问题:Java中有几种方法新建一个线程?所有人都知道,标准答案是两种:继承Thread或者实现Runnable,在JDK源代码中Thread类的注释中也是这么写的。然而在我看来这两种方法根本就是一种,所有想要开启线程的操作,

3、都必须生成了一个Thread类(或其子类)的实例,执行其中的native方法start0()。Java中的线程Java中将线程抽象为一个普通的类,这样带来了很多好处,譬如可以很简单的使用面向对象的方法实现多线程的编程,然而这种程序写多了容易会忘记,这个对象在底层是实实在在地对应了一个OS中的线程。操作系统中的线程和进程上图中的进程(Process)可以看做一个JVM,可以看出,所有的进程有自己的私有内存,这块内存会在主存中有一段映射,而所有的线程共享JVM中的内存。在现代的操作系统中,线程的调度通常都是集成在操作系统中的,操作系统能通过分析更多的信息来决定如何更高效地进行线程的调度,这也是为什

4、么Java中会一直强调,线程的执行顺序是不会得到保证的,因为JVM自己管不了这个,所以只能认为它是完全无序的。另外,类java.lang.Thread中的很多属性也会直接映射为操作系统中线程的一些属性。Java的Thread中提供的一些方法如sleep和yield其实依赖于操作系统中线程的调度算法。关于线程的调度算法可以去读操作系统相关的书籍,这里就不做太多叙述了。线程的开销通常来说,操作系统中线程之间的上下文切换大约要消耗1到10微秒从上图中可以看出线程中包含了一些上下文信息: CPU栈指针(Stack)、 一组寄存器的值(Registers), 指令计数器的值(PC)等,它们都保存在此线程

5、所在的进程所映射的主存中,而对于Java来说,这个进程就是JVM所在的那个进程,JVM的运行时内存可以简单的分为如下几部分:1. 若干个栈(Stack)。每个线程有自己的栈,JVM中的栈是不能存储对象的,只能存储基础变量和对象引用。2. 堆(Heap)。一个JVM只有一个堆,所有的对象都在堆上分配。3. 方法区(Method Area)。一个JVM只有一个方法区,包含了所有载入的类的字节码和静态变量。其中#1中的栈可以认为是这个线程的上下文,创建线程要申请相应的栈空间,而栈空间的大小是一定的,所以当栈空间不够用时,会导致线程申请不成功。在Thread的源代码中可以看到,启动线程的最后一步是执行

6、一个本地方法private native void start0(),代码1是OpenJDK中start0最终调用的方法:/代码1JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread) JVMWrapper(JVM_StartThread); JavaThread *native_thread = NULL; bool throw_illegal_thread_state = false; / We must release the Threads_lock before we can post a jvmti event /

7、 in Thread:start. MutexLocker mu(Threads_lock); /省略一些代码 jlong size = java_lang_Thread:stackSize(JNIHandles:resolve_non_null(jthread); size_t sz = size 0 ? (size_t) size : 0; native_thread = new JavaThread(&thread_entry, sz); if (native_thread-osthread() = NULL) THROW_MSG(vmSymbols:java_lang_OutOfMem

8、oryError(), unable to create new native thread Thread:start(native_thread);JVM_END从代码1中可以看到,线程的创建首先需要栈空间,所以过多的线程创建可能会导致OOM。同时,线程的切换会有以下开销:1. CPU中执行上下文的切换,导致CPU中的指令流水线(Instruction Pipeline)的中断和CPU缓存的失效。2. 如果线程太多,线程切换的时间会比线程执行的时间要长,严重浪费了CPU资源。3. 对于共享资源的竞争(锁)会导致线程切换开销急剧增加。根据以上的描述,所以通常建议尽可能创建较少的线程,减少锁的使

9、用(尤其是synchronized),尽量使用JDK提供的同步工具。而为了减少线程上下文切换带来的开销,通常使用线程池是一个有效的方法。Java中的线程池Executor框架中最常用的大概就是java.util.concurrent.ThreadPoolExecutor了,对于它的描述,简单的说就是它维护了一个线程池,对于提交到此Executor中的任务,它不是创建新的线程而是使用池内的线程进行执行。对于数量巨大但执行时间很小的任务,可以显著地减少对于任务执行的开销。java.util.concurrent.ThreadPoolExecutor中包含了很多属性,通过这些属性开发者可以定制不同的

10、线程池行为,大致如下:1. 线程池的大小:corePoolSize和maximumPoolSizeThreadPoolExecutor中线程池的大小由这两个属性决定,前者指当线程池正常运行起来后的最小(核心)线程数,当一个任务到来时,若当前池中线程数小于corePoolSize,则会生成新的线程;后者指当等待队列满了之后可生成的最大的线程数。在例1中返回的对象中这两个值相等,均等于用户传入的值。2. 用户可以通过调用java.util.concurrent.ThreadPoolExecutor上的实例方法来启动核心线程(core pool)3. 可定制化的线程生成方式:threadFactor

11、y默认线程由方法Executors.defaultThreadFactory()返回的ThreadFactory进行创建,默认创建的线程都不是daemon,开发者可以传入自定义的ThreadFactory进行对线程的定制化。5. 非核心线程的空闲等待时间:keepAliveTime6. 任务等待队列:workQueue这个队列是java.util.concurrent.BlockingQueue的一个实例。当池中当前没有空闲的线程来执行任务,就会将此任务放入等待队列,根据其具体实现类的不同,又可分为3种不同的队列策略:1. 容量为0。如:java.util.concurrent.Synchro

12、nousQueue等待队列容量为0,所有需要阻塞的任务必须等待池内的某个线程有空闲,才能继续执行,否则阻塞。调用Executors.newCachedThreadPool的两个函数生成的线程池是这个策略。2. 不限容量。不指定容量的java.util.concurrent.LinkedBlockingQueue等待队列的长度无穷大,根据上文中的叙述,在这种策略下,不会有多于corePoolSize的线程被创建,所以maximumPoolSize也就没有任何意义了。调用Executors.newFixedThreadPool生成的线程池是这个策略。3. 限制容量。指定容量的任何java.util

13、.concurrent.BlockingQueue= min) return; / replacement not needed addWorker(null, false);private boolean addWorker(Runnable firstTask, boolean core) retry: for (;) int c = ctl.get(); int rs = runStateOf(c); / Check if queue empty only if necessary. if (rs = SHUTDOWN & (rs = SHUTDOWN & firstTask = nul

14、l & workQueue.isEmpty() return false; int wc = workerCountOf(c); if (wc = CAPACITY | wc = (core ? corePoolSize : maximumPoolSize) if (compareAndIncrementWorkerCount(c) break retry; c = ctl.get(); / Re-read ctl if (runStateOf(c) != rs) continue retry; / else CAS failed due to workerCount change; retr

15、y inner loop boolean workerStarted = false; boolean workerAdded = false; Worker w = null; w = new Worker(firstTask); final Thread t = w.thread; if (t ! final ReentrantLock mainLock = this.mainLock; mainLock.lock(); / Recheck while holding lock. / Back out on ThreadFactory failure or if / shut down b

16、efore lock acquired. int rs = runStateOf(ctl.get(); if (rs largestPoolSize) largestPoolSize = s; workerAdded = true; mainLock.unlock(); if (workerAdded) t.start(); workerStarted = true; workerStarted) addWorkerFailed(w); return workerStarted;五、回到我的问题由于各种各样的原因,我们并没有使用数据库自带的主从机制来做数据的复制,而是将主库的所有DML语句作为

17、消息发送到读库(DTS),同时自己实现了数据的重放。第一版的数据同步服务十分简单,对于主库的DML消息处理和消费(写入读库)都是在一个线程内完成的.这么实现的优点是简单,但缺点是直接导致了表与表之间的数据同步会受到影响,如果有一个表A忽然来了很多的消息(往往是批量修改数据造成的),则会占住消息处理通道,影响其他业务数据的及时同步,同时单线程写库吞吐太小。上文说到,首先想到的是使用线程池来做消息的消费,但是不能直接套用上边说的Executor框架,由于以下几个原因:1. ThreadPoolExecutor中默认所有的任务之间是不互相影响的,然而对于数据库的DML来说,消息的顺序不能被打乱,至少单表的消息顺序必须有序,不然会影响最终的数据一致。2. ThreadPoolExecutor中所有的线程共享一个等待队列,然而为了防止表与表之间的影响,每个线程应该有自己的任务等待队列。3.

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1