对于时间分为 本地挂钟时间 和 UTC时间,所谓的UTC时间就是指表示自从标准基准时间(称为“历元(epoch)”,即 1970 年 1 月 1 日 00:00:00 GMT)以来的指定毫秒数 ,毫无疑问这个时间所有计算机都是一样的。那么我们任务栏上的时间是怎么回事呢?那是OS会把计算机所在的当前时区加上,如:中国在东八区,就会在UTC时间上加上 8(小时)*60*60*1000作为本地挂钟时间(不考虑夏令时)。
这篇文章主要是说明,为什么修改了“系统时区”,程序不能马上把打印时间切换到修改的时区,而是需要重新再次执行该程序的时候,才能生效(http://www.iteye.com/post/338220)。
JDK源代码中
java 代码
- private static void setDefaultZone() {
- TimeZone tz = null;
-
- String zoneID = (String) AccessController.doPrivileged(
- new GetPropertyAction("user.timezone"));
-
-
-
- if (zoneID == null || zoneID.equals("")) {
- String country = (String) AccessController.doPrivileged(
- new GetPropertyAction("user.country"));
- String javaHome = (String) AccessController.doPrivileged(
- new GetPropertyAction("java.home"));
- try {
- zoneID = getSystemTimeZoneID(javaHome, country);
- if (zoneID == null) {
- zoneID = GMT_ID;
- }
- } catch (NullPointerException e) {
- zoneID = GMT_ID;
- }
- }
-
-
-
- tz = getTimeZone(zoneID, false);
-
- if (tz == null) {
-
-
-
- String gmtOffsetID = getSystemGMTOffsetID();
- if (gmtOffsetID != null) {
- zoneID = gmtOffsetID;
- }
- tz = getTimeZone(zoneID, true);
- }
- assert tz != null;
-
- final String id = zoneID;
- AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
- System.setProperty("user.timezone", id);
- return null;
- }
- });
-
- defaultZoneTL.set(tz);
- }
显然这段代码的意思是:如果在系统变量中找不到设置的TimeZone就会设置新的,如果找到了就使用原来存在的,那为什么重新执行该程序就可以了呢?
因为这里的系统指的是JRE而不是我们的OS,当执行一个程序的时候后,JVM会创建一个JVM实例,这个实例的生命周期就是这个进程的生命的周期,我们写入的系统变量都是些入了这个JVM实例,当然再次执行这个程序,又会创建一个新的JVM实例,原来写入的系统变量也就不存在了。
这里介绍一下
java 代码
- String zoneID = (String) AccessController.doPrivileged(
- new GetPropertyAction("user.timezone"));
这是一个特权处理(摘自
http://ganzhi.bokee.com/1791837.html):
来自不同的位置的代码可以由一个CodeSource对象描述其位置和签名证书。根据代码的CodeSource的不同,代码拥有不同的权限。例如所有Java SDK自带的代码都具有所有的权限,而Applet中的代码则具有非常受限的权限,用户编写的代码可以自己定制权限(通过SecurityManager)。
当执行一段代码时,这段代码的StackTrace包含了从Main开始所有正在被调用而且没有结束的方法。在这个调用过程中,很有可能出现跨多个不同的CodeSource的调用序列。由于CodeSource不同,这些代码通常拥有不同的权限集。只有所有途经的CodeSource都具有对应的权限集合时,当前正在运行的代码才能存取某个Resource。
而doPrivileged方法是对这个规则的一种补充。他类似于Unix中的setuid程序。Unix中的login程序必须访问password文件从而获得用户授权信息,但是用户不能随意的访问password文件。因此,login程序具有setuid位,它不管被哪个用户所调用,都具有root的权限。
调用doPrivileged的方法不管其StackTrace中其他方法的权限,而仅仅根据当前方法的权限来判断用户是否能访问某个resource。也即可以规定用户只能用某种预定的方式来访问其本来不能访问的resource。
使用doPrivileged方法和使用setuid位都有需要注意的地方,例如仅执行必要的操作。否则,可能带来安全上的问题。
对于
java 代码
- new GetPropertyAction("user.timezone")
就是“利用需要取到值的系统变量名称创建GetPropertyAction对象”,该对象的作用可以在特权处理中重新得到系统变量名称代表的变量值。
这段代码是jdk1.4和1.5中的公共部分,在1.5中 增加了ThreadLocal保证不同线程逗留保留一份该时区系统属性的副本,保证同一个进程中的不同线程使用到TimeZone.getDefault()可以从ThreaLocal中直接取出!