1、Java 定时器原理是怎么样的?
解包 jdk_sec-1_5_0-src-jrl,在/j2se/src/share/classes/java/util 中找到 Timer 类。
代码语言:javascript复制private TaskQueue queue = new TaskQueue();
private TimerThread thread = new TimerThread(queue);
我找到了一个 Timer 的任务队列,找到了一个实际运行的线程类。
再来看看还有什么:
代码语言:javascript复制 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 类型实际是怎么实现的。
代码语言:javascript复制/** 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 内容实际是不可变的,举例:
代码语言:javascript复制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 接口。不过现在我们看看里面的一个有趣的方法:
代码语言:javascript复制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 为例吧,找到了一个需要变化容量的方法:
代码语言:javascript复制//这是它实际存储对象的数组
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 里的类看一看而已,相信进一步的研究会有更多收获。
文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》
×Scan to share with WeChat