Java中static和volatile的区别

今天去面试,把transient当成volatile说了,很是丢脸,今天在这里记录一下。

1. 首先说一下什么是transient。

1) transient keyword is used along with instance variables to exclude them from serialization process. if a field is transient
its value will not be persisted. see my post what is transient keyword in
java
for more details. On the other hand volatile keyword can also be
used in variables to indicate compiler and JVM that always read its value from
main memory and follow happens-before relationship on visibility of volatile
variable among multiple thread. see my post how and when to use volatile
keyword in Java
for more details.
transient就是在序列化时,标记变量,不用被序列化。

2) transient keyword can not be used along with static keyword but volatile
can be used along with static.

语义上来说,transient是可以被static修饰的,但是没有什么实际意义。

3) transient variables are initialized with default value during de-
serialization and there assignment or restoration of value has to be handled
by application code.
在反序列化时,transient变量会被初始化成初始值,应用程序自己需要自己在处理它们的值。

Read more: http://javarevisited.blogspot.com/2012/03/difference-between-
transient-and.html#ixzz2siNRg1eC

2. 啰嗦完毕,言归正传,那么static和volatile的区别是什么呢?

static是Object之间共享的变量;static变量可能会被线程cache;static可以修饰volatile
volatile是线程之间共享的变量;

http://malalanayake.wordpress.com/2013/09/12/volatile-vs-static-in-java/

http://javarevisited.blogspot.de/2011/06/volatile-keyword-
java-example-tutorial.html

例子一:

public class VolatileExample {
    public static void main(String args[]) {
        new ExampleThread("Thread 1 ").start();
        new ExampleThread("Thread 2 ").start();
    }
}

class ExampleThread extends Thread {
    private static double testValue = 1;
    private static boolean isExit = false;

    public ExampleThread(String str) {
        super(str);
    }

    @Override
    public void run() {
        if (getName().compareTo("Thread 2 ") == 0) {
            while (true) {
                System.out.println(getName() + "Test Value T2: " + testValue);

                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                if (isExit) {
                    return;
                }
            }
        }


        for (int i = 0; i < 10; i++) {
            try {
                if (getName().compareTo("Thread 1 ") == 0) {
                    testValue++;
                    System.out.println(getName() + "Test Value T1: " + testValue);

                    Thread.sleep(100);

                    if(i == 9) {
                        isExit = true;
                    }
                }                

            } catch (InterruptedException exception) {
                exception.printStackTrace();
            }
        }        
    }
}

上面的代码运行结果是:

Thread 2 Test Value T2: 2.0
Thread 1 Test Value T1: 2.0
Thread 2 Test Value T2: 2.0
Thread 2 Test Value T2: 2.0
Thread 2 Test Value T2: 2.0
Thread 2 Test Value T2: 2.0
Thread 2 Test Value T2: 2.0
Thread 2 Test Value T2: 2.0
Thread 2 Test Value T2: 2.0
Thread 2 Test Value T2: 2.0
Thread 1 Test Value T1: 3.0
Thread 2 Test Value T2: 3.0
Thread 2 Test Value T2: 3.0
Thread 2 Test Value T2: 3.0
Thread 2 Test Value T2: 3.0
Thread 2 Test Value T2: 3.0
Thread 2 Test Value T2: 3.0
Thread 2 Test Value T2: 3.0
Thread 2 Test Value T2: 3.0
Thread 1 Test Value T1: 4.0
Thread 2 Test Value T2: 4.0
Thread 2 Test Value T2: 4.0
Thread 2 Test Value T2: 4.0
Thread 2 Test Value T2: 4.0
Thread 2 Test Value T2: 4.0
Thread 2 Test Value T2: 4.0
Thread 2 Test Value T2: 4.0
Thread 2 Test Value T2: 4.0
Thread 2 Test Value T2: 4.0
Thread 1 Test Value T1: 5.0
Thread 2 Test Value T2: 5.0
Thread 2 Test Value T2: 5.0
Thread 2 Test Value T2: 5.0
Thread 2 Test Value T2: 5.0
Thread 2 Test Value T2: 5.0
Thread 2 Test Value T2: 5.0
Thread 2 Test Value T2: 5.0
Thread 2 Test Value T2: 5.0
Thread 1 Test Value T1: 6.0
Thread 2 Test Value T2: 6.0
Thread 2 Test Value T2: 6.0
Thread 2 Test Value T2: 6.0
Thread 2 Test Value T2: 6.0
Thread 2 Test Value T2: 6.0
Thread 2 Test Value T2: 6.0
Thread 2 Test Value T2: 6.0
Thread 2 Test Value T2: 6.0
Thread 2 Test Value T2: 6.0
Thread 1 Test Value T1: 7.0
Thread 2 Test Value T2: 7.0
Thread 2 Test Value T2: 7.0
Thread 2 Test Value T2: 7.0
Thread 2 Test Value T2: 7.0
Thread 2 Test Value T2: 7.0
Thread 2 Test Value T2: 7.0
Thread 2 Test Value T2: 7.0
Thread 2 Test Value T2: 7.0
Thread 1 Test Value T1: 8.0
Thread 2 Test Value T2: 8.0
Thread 2 Test Value T2: 8.0
Thread 2 Test Value T2: 8.0
Thread 2 Test Value T2: 8.0
Thread 2 Test Value T2: 8.0
Thread 2 Test Value T2: 8.0
Thread 2 Test Value T2: 8.0
Thread 2 Test Value T2: 8.0
Thread 2 Test Value T2: 8.0
Thread 1 Test Value T1: 9.0
Thread 2 Test Value T2: 9.0
Thread 2 Test Value T2: 9.0
Thread 2 Test Value T2: 9.0
Thread 2 Test Value T2: 9.0
Thread 2 Test Value T2: 9.0
Thread 2 Test Value T2: 9.0
Thread 2 Test Value T2: 9.0
Thread 2 Test Value T2: 9.0
Thread 1 Test Value T1: 10.0
Thread 2 Test Value T2: 10.0
Thread 2 Test Value T2: 10.0
Thread 2 Test Value T2: 10.0
Thread 2 Test Value T2: 10.0
Thread 2 Test Value T2: 10.0
Thread 2 Test Value T2: 10.0
Thread 2 Test Value T2: 10.0
Thread 2 Test Value T2: 10.0
Thread 2 Test Value T2: 10.0
Thread 1 Test Value T1: 11.0
Thread 2 Test Value T2: 11.0
Thread 2 Test Value T2: 11.0
Thread 2 Test Value T2: 11.0
Thread 2 Test Value T2: 11.0
Thread 2 Test Value T2: 11.0
Thread 2 Test Value T2: 11.0
Thread 2 Test Value T2: 11.0
Thread 2 Test Value T2: 11.0

从这里可以看到,static变量在不通的线程之间是可以共享的,这好像和上面说的不一样?

每次线程1改变testValue之后,线程2都能取道改变后的值。

其实例子的输出和CPU和JVM的版本都有关系,JVM不保证变量在不同的线程之间是可见的,只有线程之间建立了happen-before关系。