摘要:        起因:在写java的时候,经常遇到函数需要返回2个值或者3个值,java必须编写一个Object,来封装,但很多应用场景只是临时使用,构建对象感觉杀鸡用宰牛刀,而其他语言有比较好的实现方法。(当然通过指针引用可以解决一部分问题) 如:一般写法:     Code high...  阅读全文
posted @ 2011-10-28 18:35 胡鹏 阅读(6364) | 评论 (0)编辑 收藏
     摘要:     java.util.concurrent包分成了三个部分,分别是:                        ...  阅读全文
posted @ 2011-10-12 17:25 胡鹏 阅读(2425) | 评论 (0)编辑 收藏
      不复制内容了,可以看戏如下链接,还是有很多值得看的东东,有空看下。~

    
    http://terryblog.blog.51cto.com/1764499/547777
posted @ 2011-07-13 20:12 胡鹏 阅读(231) | 评论 (0)编辑 收藏


申请一个Android Maps API Key

1.找到你的debug.keystore文件所在的路径:
证书的一般路径为:打开eclipse,选择Windows———>Preference———>Android———>Build,其中Default debug  keystore的值便是debug.keystore的路径(windows的一般在 C:\Documents and Settings\当前用户\.android下找到debug.keystore)
2.在命令提示符中执行: keytool -list -keystore debug.keystore  (keytool是java一个命令,在%java_home%\bin里可以看到)
需要输入密码:android
然后就会得到MD5的值,进入
http://code.google.com/intl/zh-CN/android/add-ons/google-apis/maps-api-signup.html ,根据MD5值获取MAPS API KEY(前提是你必须有一个google账户)
posted @ 2011-06-18 16:37 胡鹏 阅读(974) | 评论 (0)编辑 收藏
      使input组件的绝对位置覆盖select组件的选择框,当select的状态发生改变的时候,使用this.parentNode.nextSibling.value=this.value把select所选择的值赋给input.

<HTML> 
<HEAD> 
<META http-equiv='Content-Type' content='text/html; charset=gb2312'> 
<TITLE>可输入的下拉框</TITLE> 
</HEAD> 
<BODY > 
 
<div style="position:relative;"> 
<span style="margin-left:100px;width:18px;overflow:hidden;"> 
<select style="width:118px;margin-left:-100px" onchange="this.parentNode.nextSibling.value=this.value"> 
<option value="www.taobao.com"> taobao </option> 
<option value="www.baidu.com"> soft </option> 
<option value="WEB开发者"> WEB开发者 </option> 
</select></span><input name="box" style="width:100px;position:absolute;left:0px;"> 
</div> 
</BODY></HTML> 
posted @ 2011-05-29 16:39 胡鹏 阅读(5062) | 评论 (2)编辑 收藏

单例创建模式是一个通用的编程习语。和多线程一起使用时,必需使用某种类型的同步。在努力创建更有效的代码时,Java 程序员们创建了双重检查锁定习语,将其和单例创建模式一起使用,从而限制同步代码量。然而,由于一些不太常见的 Java 内存模型细节的原因,并不能保证这个双重检查锁定习语有效。它偶尔会失败,而不是总失败。此外,它失败的原因并不明显,还包含 Java 内存模型的一些隐秘细节。这些事实将导致代码失败,原因是双重检查锁定难于跟踪。在本文余下的部分里,我们将详细介绍双重检查锁定习语,从而理解它在何处失效。

单例创建习语

要理解双重检查锁定习语是从哪里起源的,就必须理解通用单例创建习语,如清单 1 中的阐释:


清单 1. 单例创建习语
                        import java.util.*;
            class Singleton
            {
            private static Singleton instance;
            private Vector v;
            private boolean inUse;
            private Singleton()
            {
            v = new Vector();
            v.addElement(new Object());
            inUse = true;
            }
            public static Singleton getInstance()
            {
            if (instance == null)          //1
            instance = new Singleton();  //2
            return instance;               //3
            }
            }
            

此类的设计确保只创建一个 Singleton 对象。构造函数被声明为 privategetInstance() 方法只创建一个对象。这个实现适合于单线程程序。然而,当引入多线程时,就必须通过同步来保护 getInstance() 方法。如果不保护 getInstance() 方法,则可能返回 Singleton 对象的两个不同的实例。假设两个线程并发调用 getInstance() 方法并且按以下顺序执行调用:

  1. 线程 1 调用 getInstance() 方法并决定 instance 在 //1 处为 null

  2. 线程 1 进入 if 代码块,但在执行 //2 处的代码行时被线程 2 预占。

  3. 线程 2 调用 getInstance() 方法并在 //1 处决定 instancenull

  4. 线程 2 进入 if 代码块并创建一个新的 Singleton 对象并在 //2 处将变量 instance 分配给这个新对象。

  5. 线程 2 在 //3 处返回 Singleton 对象引用。

  6. 线程 2 被线程 1 预占。

  7. 线程 1 在它停止的地方启动,并执行 //2 代码行,这导致创建另一个 Singleton 对象。

  8. 线程 1 在 //3 处返回这个对象。

结果是 getInstance() 方法创建了两个 Singleton 对象,而它本该只创建一个对象。通过同步 getInstance() 方法从而在同一时间只允许一个线程执行代码,这个问题得以改正,如清单 2 所示:


清单 2. 线程安全的 getInstance() 方法
                        public static synchronized Singleton getInstance()
            {
            if (instance == null)          //1
            instance = new Singleton();  //2
            return instance;               //3
            }
            

清单 2 中的代码针对多线程访问 getInstance() 方法运行得很好。然而,当分析这段代码时,您会意识到只有在第一次调用方法时才需要同步。由于只有第一次调用执行了 //2 处的代码,而只有此行代码需要同步,因此就无需对后续调用使用同步。所有其他调用用于决定 instance 是非 null 的,并将其返回。多线程能够安全并发地执行除第一次调用外的所有调用。尽管如此,由于该方法是 synchronized 的,需要为该方法的每一次调用付出同步的代价,即使只有第一次调用需要同步。

为使此方法更为有效,一个被称为双重检查锁定的习语就应运而生了。这个想法是为了避免对除第一次调用外的所有调用都实行同步的昂贵代价。同步的代价在不同的 JVM 间是不同的。在早期,代价相当高。随着更高级的 JVM 的出现,同步的代价降低了,但出入 synchronized 方法或块仍然有性能损失。不考虑 JVM 技术的进步,程序员们绝不想不必要地浪费处理时间。

因为只有清单 2 中的 //2 行需要同步,我们可以只将其包装到一个同步块中,如清单 3 所示:


清单 3. getInstance() 方法
                        public static Singleton getInstance()
            {
            if (instance == null)
            {
            synchronized(Singleton.class) {
            instance = new Singleton();
            }
            }
            return instance;
            }
            

清单 3 中的代码展示了用多线程加以说明的和清单 1 相同的问题。当 instancenull 时,两个线程可以并发地进入 if 语句内部。然后,一个线程进入 synchronized 块来初始化 instance,而另一个线程则被阻断。当第一个线程退出 synchronized 块时,等待着的线程进入并创建另一个 Singleton 对象。注意:当第二个线程进入 synchronized 块时,它并没有检查 instance 是否非 null







双重检查锁定

为处理清单 3 中的问题,我们需要对 instance 进行第二次检查。这就是“双重检查锁定”名称的由来。将双重检查锁定习语应用到清单 3 的结果就是清单 4 。


清单 4. 双重检查锁定示例
                        public static Singleton getInstance()
            {
            if (instance == null)
            {
            synchronized(Singleton.class) {  //1
            if (instance == null)          //2
            instance = new Singleton();  //3
            }
            }
            return instance;
            }
            

双重检查锁定背后的理论是:在 //2 处的第二次检查使(如清单 3 中那样)创建两个不同的 Singleton 对象成为不可能。假设有下列事件序列:

  1. 线程 1 进入 getInstance() 方法。

  2. 由于 instancenull,线程 1 在 //1 处进入 synchronized 块。

  3. 线程 1 被线程 2 预占。

  4. 线程 2 进入 getInstance() 方法。

  5. 由于 instance 仍旧为 null,线程 2 试图获取 //1 处的锁。然而,由于线程 1 持有该锁,线程 2 在 //1 处阻塞。

  6. 线程 2 被线程 1 预占。

  7. 线程 1 执行,由于在 //2 处实例仍旧为 null,线程 1 还创建一个 Singleton 对象并将其引用赋值给 instance

  8. 线程 1 退出 synchronized 块并从 getInstance() 方法返回实例。

  9. 线程 1 被线程 2 预占。

  10. 线程 2 获取 //1 处的锁并检查 instance 是否为 null

  11. 由于 instance 是非 null 的,并没有创建第二个 Singleton 对象,由线程 1 创建的对象被返回。

双重检查锁定背后的理论是完美的。不幸地是,现实完全不同。双重检查锁定的问题是:并不能保证它会在单处理器或多处理器计算机上顺利运行。

双重检查锁定失败的问题并不归咎于 JVM 中的实现 bug,而是归咎于 Java 平台内存模型。内存模型允许所谓的“无序写入”,这也是这些习语失败的一个主要原因。







无序写入

为解释该问题,需要重新考察上述清单 4 中的 //3 行。此行代码创建了一个 Singleton 对象并初始化变量 instance 来引用此对象。这行代码的问题是:在 Singleton 构造函数体执行之前,变量 instance 可能成为非 null 的。

什么?这一说法可能让您始料未及,但事实确实如此。在解释这个现象如何发生前,请先暂时接受这一事实,我们先来考察一下双重检查锁定是如何被破坏的。假设清单 4 中代码执行以下事件序列:

  1. 线程 1 进入 getInstance() 方法。

  2. 由于 instancenull,线程 1 在 //1 处进入 synchronized 块。

  3. 线程 1 前进到 //3 处,但在构造函数执行之前,使实例成为非 null

  4. 线程 1 被线程 2 预占。

  5. 线程 2 检查实例是否为 null。因为实例不为 null,线程 2 将 instance 引用返回给一个构造完整但部分初始化了的 Singleton 对象。

  6. 线程 2 被线程 1 预占。

  7. 线程 1 通过运行 Singleton 对象的构造函数并将引用返回给它,来完成对该对象的初始化。

此事件序列发生在线程 2 返回一个尚未执行构造函数的对象的时候。

为展示此事件的发生情况,假设为代码行 instance =new Singleton(); 执行了下列伪代码: instance =new Singleton();

mem = allocate();             //Allocate memory for Singleton object.
            instance = mem;               //Note that instance is now non-null, but
            //has not been initialized.
            ctorSingleton(instance);      //Invoke constructor for Singleton passing
            //instance.
            

这段伪代码不仅是可能的,而且是一些 JIT 编译器上真实发生的。执行的顺序是颠倒的,但鉴于当前的内存模型,这也是允许发生的。JIT 编译器的这一行为使双重检查锁定的问题只不过是一次学术实践而已。

为说明这一情况,假设有清单 5 中的代码。它包含一个剥离版的 getInstance() 方法。我已经删除了“双重检查性”以简化我们对生成的汇编代码(清单 6)的回顾。我们只关心 JIT 编译器如何编译 instance=new Singleton(); 代码。此外,我提供了一个简单的构造函数来明确说明汇编代码中该构造函数的运行情况。


清单 5. 用于演示无序写入的单例类
                        class Singleton
            {
            private static Singleton instance;
            private boolean inUse;
            private int val;
            private Singleton()
            {
            inUse = true;
            val = 5;
            }
            public static Singleton getInstance()
            {
            if (instance == null)
            instance = new Singleton();
            return instance;
            }
            }
            

清单 6 包含由 Sun JDK 1.2.1 JIT 编译器为清单 5 中的 getInstance() 方法体生成的汇编代码。


清单 6. 由清单 5 中的代码生成的汇编代码
                        ;asm code generated for getInstance
            054D20B0   mov         eax,[049388C8]      ;load instance ref
            054D20B5   test        eax,eax             ;test for null
            054D20B7   jne         054D20D7
            054D20B9   mov         eax,14C0988h
            054D20BE   call        503EF8F0            ;allocate memory
            054D20C3   mov         [049388C8],eax      ;store pointer in
            ;instance ref. instance
            ;non-null and ctor
            ;has not run
            054D20C8   mov         ecx,dword ptr [eax]
            054D20CA   mov         dword ptr [ecx],1   ;inline ctor - inUse=true;
            054D20D0   mov         dword ptr [ecx+4],5 ;inline ctor - val=5;
            054D20D7   mov         ebx,dword ptr ds:[49388C8h]
            054D20DD   jmp         054D20B0
            

注: 为引用下列说明中的汇编代码行,我将引用指令地址的最后两个值,因为它们都以 054D20 开头。例如,B5 代表 test eax,eax

汇编代码是通过运行一个在无限循环中调用 getInstance() 方法的测试程序来生成的。程序运行时,请运行 Microsoft Visual C++ 调试器并将其附到表示测试程序的 Java 进程中。然后,中断执行并找到表示该无限循环的汇编代码。

B0B5 处的前两行汇编代码将 instance 引用从内存位置 049388C8 加载至 eax 中,并进行 null 检查。这跟清单 5 中的 getInstance() 方法的第一行代码相对应。第一次调用此方法时,instancenull,代码执行到 B9BE 处的代码为 Singleton 对象从堆中分配内存,并将一个指向该块内存的指针存储到 eax 中。下一行代码,C3,获取 eax 中的指针并将其存储回内存位置为 049388C8 的实例引用。结果是,instance 现在为非 null 并引用一个有效的 Singleton 对象。然而,此对象的构造函数尚未运行,这恰是破坏双重检查锁定的情况。然后,在 C8 行处,instance 指针被解除引用并存储到 ecxCAD0 行表示内联的构造函数,该构造函数将值 true5 存储到 Singleton 对象。如果此代码在执行 C3 行后且在完成该构造函数前被另一个线程中断,则双重检查锁定就会失败。

不是所有的 JIT 编译器都生成如上代码。一些生成了代码,从而只在构造函数执行后使 instance 成为非 null。针对 Java 技术的 IBM SDK 1.3 版和 Sun JDK 1.3 都生成这样的代码。然而,这并不意味着应该在这些实例中使用双重检查锁定。该习语失败还有一些其他原因。此外,您并不总能知道代码会在哪些 JVM 上运行,而 JIT 编译器总是会发生变化,从而生成破坏此习语的代码。







双重检查锁定:获取两个

考虑到当前的双重检查锁定不起作用,我加入了另一个版本的代码,如清单 7 所示,从而防止您刚才看到的无序写入问题。


清单 7. 解决无序写入问题的尝试
                        public static Singleton getInstance()
            {
            if (instance == null)
            {
            synchronized(Singleton.class) {      //1
            Singleton inst = instance;         //2
            if (inst == null)
            {
            synchronized(Singleton.class) {  //3
            inst = new Singleton();        //4
            }
            instance = inst;                 //5
            }
            }
            }
            return instance;
            }
            

看着清单 7 中的代码,您应该意识到事情变得有点荒谬。请记住,创建双重检查锁定是为了避免对简单的三行 getInstance() 方法实现同步。清单 7 中的代码变得难于控制。另外,该代码没有解决问题。仔细检查可获悉原因。

此代码试图避免无序写入问题。它试图通过引入局部变量 inst 和第二个 synchronized 块来解决这一问题。该理论实现如下:

  1. 线程 1 进入 getInstance() 方法。

  2. 由于 instancenull,线程 1 在 //1 处进入第一个 synchronized 块。

  3. 局部变量 inst 获取 instance 的值,该值在 //2 处为 null

  4. 由于 instnull,线程 1 在 //3 处进入第二个 synchronized 块。

  5. 线程 1 然后开始执行 //4 处的代码,同时使 inst 为非 null,但在 Singleton 的构造函数执行前。(这就是我们刚才看到的无序写入问题。)

  6. 线程 1 被线程 2 预占。

  7. 线程 2 进入 getInstance() 方法。

  8. 由于 instancenull,线程 2 试图在 //1 处进入第一个 synchronized 块。由于线程 1 目前持有此锁,线程 2 被阻断。

  9. 线程 1 然后完成 //4 处的执行。

  10. 线程 1 然后将一个构造完整的 Singleton 对象在 //5 处赋值给变量 instance,并退出这两个 synchronized 块。

  11. 线程 1 返回 instance

  12. 然后执行线程 2 并在 //2 处将 instance 赋值给 inst

  13. 线程 2 发现 instance 为非 null,将其返回。

这里的关键行是 //5。此行应该确保 instance 只为 null 或引用一个构造完整的 Singleton 对象。该问题发生在理论和实际彼此背道而驰的情况下。

由于当前内存模型的定义,清单 7 中的代码无效。Java 语言规范(Java Language Specification,JLS)要求不能将 synchronized 块中的代码移出来。但是,并没有说不能将 synchronized 块外面的代码移 synchronized 块中。

JIT 编译器会在这里看到一个优化的机会。此优化会删除 //4 和 //5 处的代码,组合并且生成清单 8 中所示的代码。


清单 8. 从清单 7 中优化来的代码。
                        public static Singleton getInstance()
            {
            if (instance == null)
            {
            synchronized(Singleton.class) {      //1
            Singleton inst = instance;         //2
            if (inst == null)
            {
            synchronized(Singleton.class) {  //3
            //inst = new Singleton();      //4
            instance = new Singleton();
            }
            //instance = inst;               //5
            }
            }
            }
            return instance;
            }
            

如果进行此项优化,您将同样遇到我们之前讨论过的无序写入问题。







用 volatile 声明每一个变量怎么样?

另一个想法是针对变量 inst 以及 instance 使用关键字 volatile。根据 JLS(参见 参考资料),声明成 volatile 的变量被认为是顺序一致的,即,不是重新排序的。但是试图使用 volatile 来修正双重检查锁定的问题,会产生以下两个问题:

  • 这里的问题不是有关顺序一致性的,而是代码被移动了,不是重新排序。

  • 即使考虑了顺序一致性,大多数的 JVM 也没有正确地实现 volatile

第二点值得展开讨论。假设有清单 9 中的代码:


清单 9. 使用了 volatile 的顺序一致性
                        class test
            {
            private volatile boolean stop = false;
            private volatile int num = 0;
            public void foo()
            {
            num = 100;    //This can happen second
            stop = true;  //This can happen first
            //...
            }
            public void bar()
            {
            if (stop)
            num += num;  //num can == 0!
            }
            //...
            }
            

根据 JLS,由于 stopnum 被声明为 volatile,它们应该顺序一致。这意味着如果 stop 曾经是 truenum 一定曾被设置成 100。尽管如此,因为许多 JVM 没有实现 volatile 的顺序一致性功能,您就不能依赖此行为。因此,如果线程 1 调用 foo 并且线程 2 并发地调用 bar,则线程 1 可能在 num 被设置成为 100 之前将 stop 设置成 true。这将导致线程见到 stoptrue,而 num 仍被设置成 0。使用 volatile 和 64 位变量的原子数还有另外一些问题,但这已超出了本文的讨论范围。有关此主题的更多信息,请参阅 参考资料







解决方案

底线就是:无论以何种形式,都不应使用双重检查锁定,因为您不能保证它在任何 JVM 实现上都能顺利运行。JSR-133 是有关内存模型寻址问题的,尽管如此,新的内存模型也不会支持双重检查锁定。因此,您有两种选择:

  • 接受如清单 2 中所示的 getInstance() 方法的同步。

  • 放弃同步,而使用一个 static 字段。

选择项 2 如清单 10 中所示


清单 10. 使用 static 字段的单例实现
                        class Singleton
            {
            private Vector v;
            private boolean inUse;
            private static Singleton instance = new Singleton();
            private Singleton()
            {
            v = new Vector();
            inUse = true;
            //...
            }
            public static Singleton getInstance()
            {
            return instance;
            }
            }
            

清单 10 的代码没有使用同步,并且确保调用 static getInstance() 方法时才创建 Singleton。如果您的目标是消除同步,则这将是一个很好的选择。







String 不是不变的

鉴于无序写入和引用在构造函数执行前变成非 null 的问题,您可能会考虑 String 类。假设有下列代码:

private String str;
            //...
            str = new String("hello");
            

String 类应该是不变的。尽管如此,鉴于我们之前讨论的无序写入问题,那会在这里导致问题吗?答案是肯定的。考虑两个线程访问 String str。一个线程能看见 str 引用一个 String 对象,在该对象中构造函数尚未运行。事实上,清单 11 包含展示这种情况发生的代码。注意,这个代码仅在我测试用的旧版 JVM 上会失败。IBM 1.3 和 Sun 1.3 JVM 都会如期生成不变的 String


清单 11. 可变 String 的例子
                        class StringCreator extends Thread
            {
            MutableString ms;
            public StringCreator(MutableString muts)
            {
            ms = muts;
            }
            public void run()
            {
            while(true)
            ms.str = new String("hello");          //1
            }
            }
            class StringReader extends Thread
            {
            MutableString ms;
            public StringReader(MutableString muts)
            {
            ms = muts;
            }
            public void run()
            {
            while(true)
            {
            if (!(ms.str.equals("hello")))         //2
            {
            System.out.println("String is not immutable!");
            break;
            }
            }
            }
            }
            class MutableString
            {
            public String str;                         //3
            public static void main(String args[])
            {
            MutableString ms = new MutableString();  //4
            new StringCreator(ms).start();           //5
            new StringReader(ms).start();            //6
            }
            }
            

此代码在 //4 处创建一个 MutableString 类,它包含了一个 String 引用,此引用由 //3 处的两个线程共享。在行 //5 和 //6 处,在两个分开的线程上创建了两个对象 StringCreatorStringReader。传入一个 MutableString 对象的引用。StringCreator 类进入到一个无限循环中并且使用值“hello”在 //1 处创建 String 对象。StringReader 也进入到一个无限循环中,并且在 //2 处检查当前的 String 对象的值是不是 “hello”。如果不行,StringReader 线程打印出一条消息并停止。如果 String 类是不变的,则从此程序应当看不到任何输出。如果发生了无序写入问题,则使 StringReader 看到 str 引用的惟一方法绝不是值为“hello”的 String 对象。

在旧版的 JVM 如 Sun JDK 1.2.1 上运行此代码会导致无序写入问题。并因此导致一个非不变的 String







结束语

为避免单例中代价高昂的同步,程序员非常聪明地发明了双重检查锁定习语。不幸的是,鉴于当前的内存模型的原因,该习语尚未得到广泛使用,就明显成为了一种不安全的编程结构。重定义脆弱的内存模型这一领域的工作正在进行中。尽管如此,即使是在新提议的内存模型中,双重检查锁定也是无效的。对此问题最佳的解决方案是接受同步或者使用一个 static field

posted @ 2011-05-08 19:17 胡鹏 阅读(316) | 评论 (0)编辑 收藏
薪水族如何“钱滚钱” 教你用2万赚到1000万
工薪族月薪2000元的理财窍门
在有很多的大学生都是在毕业以后选择留在自己上学的城市,一来对城市有了感情,二来也希望能在大的城市有所发展,而现在很多大城市劳动力过剩,大学生想找到一个自己喜欢又有较高收入的职位已经变得非常难,很多刚毕业的朋友的月收入都可能徘徊在2000元人民币左右,如果您是这样的情况,让我们来核算一下,如何利用手中的有限资金来进行理财。如果您是单身一人,月收入在2000人民币,又没有其他的奖金分红等收入,那年收入就固定在25000元左右。如何来支配这些钱呢?
生活费占收入30%-40%
首先,你要拿出每个月必须支付的生活费。如房租、水电、通讯费、柴米油盐等,这部分约占收入三分之一。它们是你生活中不可或缺的部分,满足你最基本的物质需求。离开了它们,你就会像鱼儿离开了水一样无法生活,所以无论如何,请你先从收入中抽出这部分,不要动用。
储蓄占收入10%-20%
其次,是自己用来储蓄的部分,约占收入的10%-20%。很多人每次也都会在月初存钱,但是到了月底的时候,往往就变成了泡沫,存进去的大部分又取出来了,而且是不知不觉的,好像凭空消失了一样,总是在自己喜欢的衣饰、杂志、CD或朋友聚会上不加以节制。你要自己提醒自己,起码,你的存储能保证你3个月的基本生活。要知道,现在很多公司动辄减薪裁员。如果你一点储蓄都没有,一旦工作发生了变动,你将会非常被动。
而且这3个月的收入可以成为你的定心丸,工作实在干得不开心了,忍无可忍无需再忍时,你可以潇洒地对老板说声“拜拜”。想想可以不用受你不喜欢的工作和人的气,是多么开心的事啊。所以,无论如何,请为自己留条退路。
活动资金占收入30%~40%
剩下的这部分钱,约占收入的三分之一。可以根据自己当时的生活目标,侧重地花在不同的地方。譬如“五一”、“十一”可以安排旅游;服装打折时可以购进自己心仪已久的牌子货;还有平时必不可少的购买CD、朋友聚会的开销。这样花起来心里有数,不会一下子把钱都用完。
最关键的是,即使一发薪水就把这部分用完了,也可当是一次教训,可以惩罚自己一个月内什么都不能再干了(就当是收入全部支出了吧),印象会很深刻而且有效。
除去吃、穿、住、行以及其他的消费外,再怎么节省,估计您现在的状况,一年也只有10000元的积蓄,想来这些都是刚毕业的绝大部分学生所面临的实际情况。如何让钱生钱是大家想得最多的事情,然而,毕竟收入有限,很多想法都不容易实现,建议处于这个阶段的朋友,最重要的是开源,节流只是我们生活工作的一部分,就像大厦的基层一样。而最重要的是怎样财源滚滚、开源有道,为了达到一个新目标,你必须不断进步以求发展,培养自己的实力以求进步,这才是真正的生财之道。可以安心地发展自己的事业,积累自己的经验,充实自己,使自己不断地提高,才会有好的发展,要相信“机会总是给有准备的人”。
当然,既然有了些许积蓄,也不能让它闲置,我们建议把1万元分为5份,分成5个2000元,分别作出适当的投资安排。这样,家庭不会出现用钱危机,并可以获得最大的收益。
(1)用2000元买国债,这是回报率较高而又很保险的一种投资。
(2)用2000元买保险。以往人们的保险意识很淡薄,实际上购买保险也是一种较好的投资方式,而且保险金不在利息税征收之列。尤其是各寿险公司都推出了两全型险种,增加了有关“权益转换”的条款,即一旦银行利率上升,客户可在保险公司出售的险种中进行转换,并获得保险公司给予的一定的价格折扣、免予核保等优惠政策。
(3)用2000元买股票。这是一种风险最大的投资,当然风险与收益是并存的,只要选择得当,会带来理想的投资回报。除股票外,期货、投资债券等都属这一类。不过,参与这类投资,要求有相应的行业知识和较强的风险意识。
(4)用2000元存定期存款,这是一种几乎没有风险的投资方式,也是未来对家庭生活的一种保障。
(5)用2000元存活期存款,这是为了应急之用。如家里临时急需用钱,有一定数量的活期储蓄存款可解燃眉之急,而且存取又很方便。
这种方法是许多人经过多年尝试后总结出的一套成功的理财经验。当然,各个家庭可以根据不同情况,灵活使用。
正确理财三个观念
建立理财观念一:理财是一件正大光明的事,“你不理财,财不理你”。
建立理财观念二:理财要从现在开始,并长期坚持。
建立理财观念三:理财目的是“梳理财富,增值生活”。
理财四个误区
理财观念误区一:我没财可理;
理财观念误区二:我不需要理财;
理财观念误区三:等我有了钱再理财;
理财观念误区四:会理财不如会挣钱。
理财的五大目标
目标一:获得资产增值;
目标二:保证资金安全;
目标三:防御意外事故;
目标四:保证老有所养;
目标五:提供赡养父母及抚养教育子女的基金。
--------------------精彩阅读推荐--------------------
【500强企业的薪水有多高?】
全球500强大企业的薪水实情大揭密
不一定要是自己的offer letter上的数据,凡是能够确认比较准确的公司薪水都可补充。补充的话最好说明职位、本硕区别、多少个月工资、奖金。宝洁:本7200、研8200、博9700,均14个月,另有交通补助,区域补助等,CBD,marketing每几个月涨20%-30%不定。
【工薪族的你跑赢通胀了吗?】
工薪族理财跑赢通胀 开源节流资产合理配备
龙先生家是典型的工薪阶层。龙先生47岁,是某大型企业的技术师,年收入5.5万元,购买了各类基本保险。太太42岁,是某商场的合同工,年收入4万元,购买了基本的社会保险。两人均在单位吃中午饭,搭班车上下班。儿子16岁,尚在读高中。
【怎样才能钱生钱?】
“阶梯存储”应对利率调整 学三招轻松钱生钱
当前,储蓄依然在居民理财的投资组合中占据着重要地位,但在当前的加息周期内,一些人因缺乏科学的储蓄理财规划而损失利息收入。理财专家建议,进入加息周期,为了使储蓄理财能赚取更多的利息收入,储户应在存款期限、存款金额和存款方式上注意以下几点。
【爷们的脸往哪搁!】
女人太会赚钱也是错? 爷们儿的脸往哪搁
女人财大就气粗?别偏激,妻子赚钱自己也是受益者,所以首先心态放平和些,别太执着于传统的思维和他人的看法。会不会赚钱是女人衡量男人的重要标尺。男人没钱,女人觉得没有面子,不愿提及她的男人;有钱男人不怕提及他女人,无论漂亮与否,只要不给他戴绿帽子。
posted @ 2011-03-10 20:07 胡鹏 阅读(134) | 评论 (0)编辑 收藏
       

        说起精致,最容易想起的词大概是瓷器了,但这个词用到程序员身上,肯定让很多人觉得摸不着头脑,在详述"精致"这个词以前,还是先来看一个"破窗理论",让我们真正的理解"精致"的概念。

       最早的"破窗理论",也称"破窗谬论",源自于一位经济学家黑兹利特(也有人说源于法国19世纪经济学家巴斯夏),用来指出"破坏创造财富"的概念,以彻底地否定凯恩斯主义的政府干预政策。但后来美国斯坦福大学心理学家詹巴斗和犯罪学家凯琳也提出了相应的"破窗理论"。

        心理学家詹巴斗进行了一项试验,他把两辆一模一样的汽车分别停放在帕罗阿尔托的中产阶级社区和相对杂乱的布朗克斯街区。对停在布朗克斯街区的那一辆,他摘掉了车牌,并且把顶棚打开,结果不到一天就被人偷走了;而停放在帕罗阿尔托的那一辆,停了一个星期也无人问津。后来,詹巴斗用锤子把这辆车的玻璃敲了个大洞,结果仅仅过了几个小时车就不见了。

       而犯罪学家凯琳曾注意到一个问题:在她上班的路旁,有一座非常漂亮的大楼,有一天,她注意到楼上有一窗子的玻璃被打破了,那扇破窗与整座大楼的整洁美丽极不调谐,显得格外的刺眼。又过了一段时间,她惊奇地发现:那扇破窗不但没得到及时的维修,反而又增加了几个带烂玻璃的窗子……这一发现使她的心中忽有所悟:如果有人打坏了一个建筑物的窗户玻璃,而这扇窗户又得不到及时维修的话,别人就可能受到某些暗示性的纵容去打烂更多的玻璃。久而久之,这些破窗户就给人造成一种无序的感觉;其结果是:在这种麻木不仁的氛围中,犯罪就会滋生。这就是凯琳著名的"破窗理论"。

        后来的"破窗理论",已经突破原有经济学上的概念,有了新的意义:残缺不全的东西更容易遭受到别人的破坏。前面的汽车和窗户都表明了这一点。

       其实作为程序员开发软件也是一样,可能有十种好的方法去写一个功能,一个类,但同时可能会有一百种更快捷但不好的方法去做同样的事情,很多程序员会因为各种原因,如时间压力,工作强度,技术水平等一系列问题选择了后者而非前者。同样的事情还发生在维护和修改阶段,当看到别人的代码写的随意,不好时,那么自然就会沿着别人的方向走下去,结果就是产生出更多不好的代码,这是在代码开发中的一个典型"破窗理论"的体现。

   承认一点,现实世界是不完美,特别是开发中,因为时间,精力,能力等各种因素,我们始终是要打破一些窗户,但是却要记住两点:
        1.一个月前多打破了一扇窗户,结果一个月就会打破10 扇甚至更多的窗户。
        2.如果打破了一扇窗户,就要记住,迟早应该将它补上。

        因为各方面的原因,一个程序员也许不能做到精致的代码,但是如果一个程序员不想去做精致的代码,那么又何必选择软件开发呢?
posted @ 2011-01-11 22:35 胡鹏 阅读(170) | 评论 (0)编辑 收藏
 

最近有Java解压缩的需求,java.util.zip实在不好用,对中文支持也不行。所以选择了强大的TrueZIP,使用时遇到了一个问题,做个记录。
解压缩代码如下:

ArchiveDetector detector = new DefaultArchiveDetector(ArchiveDetector.ALL,
        new Object[] { "zip", new CheckedZip32Driver("GBK") } );
File zipFile = new File("zipFile", detector);
File dst = new File("dst");
// 解压缩
zipFile.copyAllTo(dst);

代码十分简洁,注意这个File是

de.schlichtherle.io.File

不是

java.io.File

当处理完业务要删除这个Zip File时,问题出现了:
这个文件删不掉!!!
把自己的代码检查了好久,确认没问题后,开始从TrueZIP下手,发现它有特殊的地方的,是提示过的:

File file = new File(“archive.zip”); // de.schlichtherle.io.File!
Please do not do this instead:
de.schlichtherle.io.File file = new de.schlichtherle.io.File(“archive.zip”);


This is for the following reasons:
1.Accidentally using java.io.File and de.schlichtherle.io.File instances referring to the same path concurrently will result in erroneous behaviour and may even cause loss of data! Please refer to the section “Third Party Access” in the package Javadoc of de.schlichtherle.io for for full details and workarounds.
2.A de.schlichtherle.io.File subclasses java.io.File and thanks to polymorphism can be used everywhere a java.io.File could be used.

原来两个File不能交叉使用,搞清楚原因了,加这么一句代码搞定。

zipFile.deleteAll();

posted @ 2011-01-11 22:30 胡鹏 阅读(1261) | 评论 (0)编辑 收藏
http://www.blogjava.net/Files/lsbwahaha/ANTLR_info.pdf
antlr简介


目前的ANTLR支持的语法层的选项主要包括:

语言选项(Language)、

输出选项(output)、

回溯选项(backtrack)、

记忆选项 memorize)、

记号词库(tokenVocab)、

重写选项(rewrite)、

超类选项(superClass)、

过滤选项(Filter)、

AST标签类型(ASTLabelType

K选项

 

 

/**
        //一些写法







k=2;

        backtrack=true;

        memoize=true;

*/

 

1.   语言选项 language

 

语言选项指定了ANTLR将要产生的代码的目标语言,默认情况下该选项设置为了Java。需要注意的是,ANTLR中的嵌入的动作必须要使用目标语言来写。

grammar T;
options {
    language=Java;
}

 

ANTLR使用了特有的基于字串模板(StringTemplate-based)代码生成器,构建一个新的目标语言显得较为简单,因此我们可以构建多种 语言,诸如JavaCC++C#PythonObjective-CRuby等等。语言选项让ANNTLR去模板目录(例如 org/antlr/codegen/templates/Java or org/antlr/codegen/templates/C)下寻找合适的模板,并使用模板来构建语言。该目录下包含大量的模板,我们可以向其中加入其 他的模板以满足我们的需求。

2.   输出选项 output

输出选项控制了ANTLR输出的数据结构,目前支持两种输出:抽象语法树——ASTAbstract Syntax Trees)和字串模板(StringTemplates——template。当output这个选项被设置后,所有的规则都被输出成了AST或者 template

grammar T;
options {
    output=AST;
}

 

3.   回溯选项backtrack

当回溯选项打开的时候,在执行一个LL(K)失败的时候,ANTLR会返回至LL(K)开始而尝试其他的规则。

 

4.   记忆选项 memorize

memoize选项打开以后,每条解析方法(Paser Method)开始之前,ANTLR会首先检测以前的尝试结果,并在该方法执行完成之后记录该规则是否执行成功。但是注意,对于单条的规则打开此选项经常比在全局上打开该规则效率更高。

 

5.   记号词库(tokenVocab

说白了就是output输出目录中的XX.tokens文件中的定义可以方便的给 大型工程中多个.g中的符号同步更新。

 

大型的工程中常常利用AST作为中间产物对输入进行多次分析并最终生成代码。对AST的遍历时需要经常使用树语法(tree grammar),而tree grammar中经常需要将符号与其他的文件中的符号进行同步或者更新。tokenVocab实现了这个功能。
例如我们定义了下面的一个语法文件:

grammar P;
options {
    output=AST;
}
expr: INT ('+' ^ INT)* ;
INT : '0'..'9' +;
WS : ' ' | '\r' | '\n' ;
利用该文件生成了一个标记:P.token,并生成了语法树(AST)。这时我们需要一个用于遍历该ASTtree grammar,并通过tree grammar 中的tokenVocab选项来向其中更新tokens:

tree grammar Dump;
options {
    tokenVocab=P;
    ASTLabelType=CommonTree;
}
expr: ^( '+' expr {System.out.print('+' );} expr )
    | INT {System.out.print($INT.text);}
    ;

编译tree grammar的时候ANTLR默认会在当前目录下寻找.token文件,我们可以通过-lib选项来设置用于寻找.token文件的目录,例如:
java org.antlr.Tool -lib . Dump.g

6.   重写选项(rewrite

通过重写选项可以改变ANTLR对输入的默认处理规则,一般用在输出为template的情况下。将该选项使能之后,ANTLR将一般的输入直接拷贝至输出,而将适于模板重写规则的输入做其他的处理。

7.   超类选项(superClass

用于指定一个超类。

8.   过滤选项(Filter

9.   AST标签类型(ASTLabelType

10.             K选项

   K选项用于限制对LL(K)进行语法分析的次数,从而提高了ANTLR的解析速度。K只能为*或者数字,默认为*

 

 

 

 

属性和动作

动作(Actions)实际上是用目标语言写成的、嵌入到规则中的代码(以花括号包裹)。它们通常直接操作输入的标号,但是他们也可以用来调用相应的外部代码。属性,到目前为止我的理解还不多,感觉像是C++中类里面的成员,一会看完应该会更清楚一些。

1.
语法动作(Grammar Actions
动作(Actions)是指嵌在语法中的、用目标语言写成的代码片段。ANTLR则把这些代码(除了用$%标记的以外)逐字地插入到生成的识别器中。
动作可以放到规则的外边,也可以嵌入到某条规则当中。当动作位于规则之外时候,这些动作同城定义了一些全局的或者是类的成员(变量或者成员函数);而当其嵌入规则之中时,则用于执行某些特定的命令,这些命令在识别器识别了其预订的字符的时候就会开始执行。例如下面的例子:

parser grammar T;
@header {
    package p;
}
@members {
    int i;
    public TParser(TokenStream input, int foo) {
        this(input);
        i = foo;
    }
}
a[int x] returns [int y]
@init {int z=0;}
@after {System.out.println("after matching rule; before finally");}
: {
action1} A {action2 }
;
catch[RecognitionException re] {
    System.err.println("error");
}
finally {
do-this-no-matter-what }

从中可以看出,前面的两个动作,@head and @members是两个处于规则之外的全局的动作,定义了一些变量和类;而后两个则分别在a这个规则的前后执行(@init在前,@after在后,这个在前面提到过)。 这里针对两种类型详细叙述。


antlr简介
posted @ 2010-12-17 19:20 胡鹏 阅读(1488) | 评论 (0)编辑 收藏
仅列出标题
共10页: 上一页 1 2 3 4 5 6 7 8 9 下一页 Last 

导航

<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

统计

常用链接

留言簿(3)

随笔分类

随笔档案

agile

搜索

最新评论

阅读排行榜

评论排行榜