解包 jdk_sec-1_5_0-src-jrl,在/j2se/src/share/classes/java/util 中找到 Timer 类。
private TaskQueue queue = new TaskQueue(); private TimerThread thread = new TimerThread(queue);
我找到了一个 Timer 的任务队列,找到了一个实际运行的线程类。
再来看看还有什么:
private void mainLoop() { while (true) { try { TimerTask task; boolean taskFired; synchronized(queue) { // Wait for queue to become non-empty while (queue.isEmpty() && newTasksMayBeScheduled) queue.wait(); if (queue.isEmpty()) break; // Queue is empty and will forever remain; die // Queue nonempty; look at first evt and do the right thing long currentTime, executionTime; task = queue.getMin(); synchronized(task.lock) { if (task.state == TimerTask.CANCELLED) { queue.removeMin(); continue; // No action required, poll queue again } currentTime = System.currentTimeMillis(); executionTime = task.nextExecutionTime; if (taskFired = (executionTime<=currentTime)) { if (task.period == 0) { // Non-repeating, remove queue.removeMin(); task.state = TimerTask.EXECUTED; } else { // Repeating task, reschedule queue.rescheduleMin( task.period<0 ? currentTime - task.period : executionTime + task.period); } } } if (!taskFired) // Task hasn't yet fired; wait queue.wait(executionTime - currentTime); } if (taskFired) // Task fired; run it, holding no locks task.run(); } catch(InterruptedException e) { } } }
这是最核心的死循环方法,可以看见,在循环中通过不断地获取系统时间,直到特定时间到达。和我以前的理解可不一样。
2、String 类型实际是怎么实现的。
/** The value is used for character storage. */ private final char value[]; /** The offset is the first index of the storage that is used. */ private final int offset; /** The count is the number of characters in the String. */ private final int count; /** Cache the hash code for the string */ private int hash; // Default to 0
看到了一个 char 类型数组,它才是实现 String 的根本,还有几个辅助属性。值得注意的是,String 内容实际是不可变的,举例:
public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } char buf[] = new char[count + otherLen]; getChars(0, count, buf, 0); str.getChars(0, otherLen, buf, count); return new String(0, count + otherLen, buf); }
这是其中的一个字符串连接的方法,可以看到 String 所有的方法,只要是牵涉到对字符串更改的,一律调用构造器生成一个新的返回,而根本不更改本身的内容,不过 StringBuffer 的内容却是可变的,看源码便知。
3、关于 Thread 类 sleep 方法参数里的纳秒。
我们都知道 Thread 实现了 Runnable 接口。不过现在我们看看里面的一个有趣的方法:
public static void sleep(long millis, int nanos) throws InterruptedException { if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException("nanosecond timeout value out of range"); } if (nanos >= 500000 || (nanos != 0 && millis == 0)) { millis++; } sleep(millis); }
看到了吧,纳秒——根本就是假的,我们都被 JDK 骗了。Java 常规控制线程的时间精度是非常低的,根本不可能接近纳秒的级别,至于你传入的纳秒参数,下场就是要么变成 0,要么变成 1 毫秒。
4、容器类的容量变化的实现。
以 Vector 为例吧,找到了一个需要变化容量的方法:
//这是它实际存储对象的数组 protected Object[] elementData; private void ensureCapacityHelper(int minCapacity) { int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object[] oldData = elementData; int newCapacity = (capacityIncrement > 0) ? (oldCapacity + capacityIncrement) : (oldCapacity * 2); if (newCapacity < minCapacity) { newCapacity = minCapacity; } elementData = new Object[newCapacity]; System.arraycopy(oldData, 0, elementData, 0, elementCount); } }
可以看到它的容器大小增长策略,如果有合理的增量,当然听用户的,否则简单地乘 2 完事。
这只是随便挑了几个感兴趣的 JDK 里的类看一看而已,相信进一步的研究会有更多收获。
文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》