按月存档: 2012/08

闲聊ClassLoader

分类:java评论:5条作者:ticmy日期:2012-08-29

Java使用类加载器来装载字节码到内存,以便后续用来创建对象调用方法等。就目前的JVM,要说这个ClassLoader,先要说到它的委托模型(有人将parent译作双亲,双亲委派模型,窃以为,很不准确,原因在说完这个委托模型之后讲)。何为委托模型?java.lang.ClassLoader有这样的描述: 每个 ClassLoader 实例都有一个相关的父类加载器。 需要查找类或资源时,ClassLoader 实例会在试图亲自查找类或资源之前,将搜索类或资源的任务委托给其父类加载器。 虚拟机的内置类加载器(称为 "bootstrap class loader")本身没有父类加载器,但是可以将它用作 ClassLoader 实例的父类加载器。 开始说“每个 ClassLoader 实例都有一个相关的父类加载器”,后面又说“虚拟机的内置类加载器(称为 “bootstrap class loader”)本身没有父类加载器”,这不是自行矛盾吗!其实不然,前面说的“每个 ClassLoader 实例”指的是每个java.lang.ClassLoader(该类是抽象类)子类的对象。而bootstrap class loader(后面叫它引导类加载器)是jvm内部由c++实现的,并不继承java.lang.ClassLoader类,所以它不属于“ClassLoader 实例”,也没有办法在Java代码…
Tags: ,

JDBC在getConnection之前为什么要调用Class.forName

分类:java, 基础评论:15条作者:ticmy日期:2012-08-24

获取一个数据库连接的通用模板如下: String driver = "oracle.jdbc.OracleDriver"; String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl"; String user = "scott"; String password = "ticmy"; Class.forName(driver); Connection conn = DriverManager.getConnection(url, user, password); 里面有个Class.forName(driver),这句话有什么作用?将驱动类load到内存?如果没有这句会怎么样?运行发现,如果去掉这一句会有以下异常: java.sql.SQLException: No suitable driver found for xxx…. 在解释具体原因之前先简单看下Class.forName做了什么。 假设一个类以前从来没有被装进内存过,Class.forName(String className)这个方法会做以下几件事情: 1、装载。将字节码读入内存,并产生一个与之对应的java.lang.Class类对象 2、连接。这一步会验证字节码,为static变量分配内存,并赋默认值(0或null),并可选的解析符号引用(这里不理解没关系) 3、初始化。为类的static变量赋初始值,假如有static int a = 1;这个将a赋值为1的操作就是这个时候做的。除此之外,还要调用类的static…
Tags:

hotspot1.7 ThreadPoolExecutor代码解析

分类:java, 并发评论:5条作者:ticmy日期:2012-08-20

写在开头:此文基于hotspot1.7.0(build 1.7.0-b147),1.6及以前的版本与1.7的版本实现上差别很大。线程池的逻辑非常复杂,原因在于线程池是有状态的(不是狭隘的指RUNNING,SHUTDOWN这些状态,而是一个类的状态,可以理解成对象的共享字段),而为了保证可伸缩性与效率,很多地方在访问这些状态的时候都没有使用锁来保证互斥访问,而采用的是多次检测。这意味着会有很多竞态条件的出现,在分析某个方法的时候,要同时想到多线程间多个方法的交互,要考虑它们的交错执行。这里只分析核心重要的方法,其它方法相对简单,就不多言了。限于本人知识、眼界有限,对于一些代码逻辑的解释极可能没有考虑周全,错漏之处也在所难免。看官自己把握,也欢迎留言指正。 线程池内部有一些状态,先来了解下这些状态的机制。以下用代码注释的方式来解释其中的含义。 /* 这个是用一个int来表示workerCount和runState的,其中runState占int的高3位, 其它29位为workerCount的值。 workerCount:当前活动的线程数; runState:线程池的当前状态。 用AtomicInteger是因为其在并发下使用compareAndSet效率非常高; 当改变当前活动的线程数时只对低29位操作…

警惕hotspot1.6及之前ThreadPoolExecutor的bug

分类:java, 并发评论:5条作者:ticmy日期:2012-08-15

近来阅读ThreadPoolExecutor的源码(jdk版本:1.6.0_26),发现有些问题。毕竟是出自并发大神Doug Lea之手,不敢有过多质疑,经测试确实出现了不合理之处,并在后续版本中有修正。 发现两个问题,其中有一个比较严重。先讲这个比较严重的。 在ThreadPoolExecutor$Worker的run方法的源码如下: public void run() { try { Runnable task = firstTask; firstTask = null; while (task != null || (task = getTask()) != null) { runTask(task); task = null; } } finally { workerDone(this); } } 线程池里的线程在while里不停的去workQueue里取任务并执行任务。当在执行任务的时候(runTask中最重要的事情就是调用了传入的task的run方法),如果task的run抛出异常,runTask方法并没有吞掉该异常,它会继续往外抛,这会导致退出ThreadPoolExecutor$Worker#run中的while循环,并最终进入到finally中的workerDone方法,workerDone方法做了什么呢?源码如下: void workerDone(Worker w) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { completedTaskCount += w.comple…