`

看源码,解疑惑

阅读更多

看JDK源码,解疑惑

 

从SUN公司主页上搞下来JDK5.0的源码,可以好好研究了。开始吧。

 

1、Java定时器原理是怎么样的?

解包jdk_sec-1_5_0-src-jrl,在/j2se/src/share/classes/java/util中找到Timer类。

  1. privateTaskQueuequeue=newTaskQueue();
  2. privateTimerThreadthread=newTimerThread(queue);

我们找到了一个Timer的任务队列,找到了一个实际运行的线程类。

再来看看还有什么:

  1. privatevoidmainLoop(){
  2. while(true){
  3. try{
  4. TimerTasktask;
  5. booleantaskFired;
  6. synchronized(queue){
  7. //Waitforqueuetobecomenon-empty
  8. while(queue.isEmpty()&&newTasksMayBeScheduled)
  9. queue.wait();
  10. if(queue.isEmpty())
  11. break;//Queueisemptyandwillforeverremain;die
  12. //Queuenonempty;lookatfirstevtanddotherightthing
  13. longcurrentTime,executionTime;
  14. task=queue.getMin();
  15. synchronized(task.lock){
  16. if(task.state==TimerTask.CANCELLED){
  17. queue.removeMin();
  18. continue;//Noactionrequired,pollqueueagain
  19. }
  20. currentTime=System.currentTimeMillis();
  21. executionTime=task.nextExecutionTime;
  22. if(taskFired=(executionTime<=currentTime)){
  23. if(task.period==0){//Non-repeating,remove
  24. queue.removeMin();
  25. task.state=TimerTask.EXECUTED;
  26. }else{//Repeatingtask,reschedule
  27. queue.rescheduleMin(
  28. task.period<0?currentTime-task.period
  29. :executionTime+task.period);
  30. }
  31. }
  32. }
  33. if(!taskFired)//Taskhasn'tyetfired;wait
  34. queue.wait(executionTime-currentTime);
  35. }
  36. if(taskFired)//Taskfired;runit,holdingnolocks
  37. task.run();
  38. }catch(InterruptedExceptione){
  39. }
  40. }
  41. }

这是最核心的死循环方法,可以看见,在循环中通过不断地获取系统时间,直到特定时间到达。

-------------------------------------------------------我是无聊的分割线-------------------------------------------------------------------

2、String类型实际是怎么实现的。

  1. /**Thevalueisusedforcharacterstorage.*/
  2. privatefinalcharvalue[];
  3. /**Theoffsetisthefirstindexofthestoragethatisused.*/
  4. privatefinalintoffset;
  5. /**ThecountisthenumberofcharactersintheString.*/
  6. privatefinalintcount;
  7. /**Cachethehashcodeforthestring*/
  8. privateinthash;//Defaultto0

看到了一个char类型数组,它才是实现String的根本,还有几个辅助属性。值得注意的是,String内容实际是不可变的,举例:

  1. publicStringconcat(Stringstr){
  2. intotherLen=str.length();
  3. if(otherLen==0){
  4. returnthis;
  5. }
  6. charbuf[]=newchar[count+otherLen];
  7. getChars(0,count,buf,0);
  8. str.getChars(0,otherLen,buf,count);
  9. returnnewString(0,count+otherLen,buf);
  10. }

这是其中的一个字符串连接的方法,可以看到String所有的方法,只要是牵涉到对字符串更改的,一律调用构造器生成一个新的返回,而根本不更改本身的内容,不过StringBuffer的内容却是可变的,看源码便知。

 

-------------------------------------------------------我是可爱的分割线-------------------------------------------------------------------

 

3、关于Thread。

我们都知道Thread实现了Runnable接口。不过现在我们看看里面的一个有趣的方法:

  1. publicstaticvoidsleep(longmillis,intnanos)
  2. throwsInterruptedException{
  3. if(millis<0){
  4. thrownewIllegalArgumentException("timeoutvalueisnegative");
  5. }
  6. if(nanos<0||nanos>999999){
  7. thrownewIllegalArgumentException(
  8. "nanosecondtimeoutvalueoutofrange");
  9. }
  10. if(nanos>=500000||(nanos!=0&&millis==0)){
  11. millis++;
  12. }
  13. sleep(millis);
  14. }

看到了吧,纳秒——根本就是假的,我们都被JDK骗了。Java常规控制线程的时间精度是非常低的,根本不可能接近纳秒的级别,至于你传入的纳秒参数,下场就是要么变成0,要么变成1毫秒。

 

-------------------------------------------------------我是傻帽的分割线-------------------------------------------------------------------

4、容器类的容量变化的实现:

以Vector为例吧,找到了一个需要变化容量的方法:

  1. //这是它实际存储对象的数组
  2. protectedObject[]elementData;
  3. privatevoidensureCapacityHelper(intminCapacity){
  4. intoldCapacity=elementData.length;
  5. if(minCapacity>oldCapacity){
  6. Object[]oldData=elementData;
  7. intnewCapacity=(capacityIncrement>0)?
  8. (oldCapacity+capacityIncrement):(oldCapacity*2);
  9. if(newCapacity<minCapacity){
  10. newCapacity=minCapacity;
  11. }
  12. elementData=newObject[newCapacity];
  13. System.arraycopy(oldData,0,elementData,0,elementCount);
  14. }
  15. }

可以看到它的容器大小增长策略,如果有合理的增量,当然听用户的,否则简单地乘2完事。

这只是随便挑了几个JDK的类看一看而已,相信进一步的研究会有更多收获。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics