`
xiaobian
  • 浏览: 588210 次
  • 来自: 北京
社区版块
存档分类
最新评论

[转载]关于native,transient,volatile,synchronized四个关键字

阅读更多
http://www.blogjava.net/bacoo/archive/2007/12/20/169172.html

[转载]关于native,transient,volatile,synchronized四个关键字的使用
native
当你需要调用本地程序的时候
transient
你的类实现了java.io.Serializable而你又不想保存某个字段的时候
volatile
这个字段会被其他线程(直接或者间接)访问到,而你想保证每个线程都能得到最新的数据
(性能上肯定有损耗的,为了安全牺牲性能的事情多着去了)
------------------------------------------------------------------------------------
3,volatile
原CSDN有一篇介绍过,现贴回来。
volatile修饰变量。在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。 
看看Java Language Specification中的例子。 
条件:一个线程不停的调用方法one(),一个线程不停的调用方法two()。我测试过多次,这种情况好像一直没有出现。 
代码
class Test {   
    static int i = 0, j = 0;   
    static void one() { i++; j++; }   
    static void two() {   
        System.out.println("i=" + i + " j=" + j);   
    }   
}   
结果偶尔会出现j大于i的情况,因为方法没有同步,所以会出现i和j可能不是一次更新。一种防止这种情况发生的办法就是声明两个方法为synchronized 的。 
代码
class Test {   
    static int i = 0, j = 0;   
    static synchronized void one() { i++; j++; }   
    static synchronized void two() {   
        System.out.println("i=" + i + " j=" + j);   
    }   
}   
这样可以防止两个方法同时被执行,还可以保证j和i被同时更新,这样一来i和j的值一直是一样的。 
另外一种途径就是把i和j声明为volatile。 
代码
class Test {   
    static volatile int i = 0, j = 0;   
    static void one() { i++; j++; }   
    static void two() {   
        System.out.println("i=" + i + " j=" + j);   
    }   
}  
------------------------------------------------------------------------------------
2,transient
transient是一个变量修饰符,标记为transient的变量,在对一个对象进行序列化时,这些变量状态不会被序列化。
例如,假设某个类的成员变量是transient,那么当通过ObjectOutputStream把这个类的某个实例保存到磁盘上时,实际上transient变量的值是不会保存的。
当对象序列化的保存在存储器上时,不希望有些字段数据被保存,为了保证安全性,可以把这些字段声明为transient。
要更明白,可以看一些序列化的内容。
------------------------------------------------------------------------------------
1,native是方法修饰符。Native方法是由另外一种语言(如c/c++,FORTRAN,汇编)实现的本地方法。一般用于JNI中。
public class testdll 

static 

System.loadLibrary("test"); 

    public native static int get(); 
    public native static void set(int i); 
    public static void main(String[] args) 
    { 
testdll test = new testdll(); 
test.set(10); 
System.out.println(test.get()); 


test.dll可以用VC写,例如,
-----testdll.h-----
/* DO NOT EDIT THIS FILE - it is machine generated */
#include  <jni.h >
/* Header for class testdll */
#ifndef _Included_testdll
#define _Included_testdll
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:     testdll
* Method:    get
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_testdll_get
  (JNIEnv *, jclass);
/*
* Class:     testdll
* Method:    set
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_testdll_set
  (JNIEnv *, jclass, jint);
#ifdef __cplusplus
}
#endif
#endif
-------testdll.c-----------
#include "testdll.h" 
int i = 0; 
JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass) 

return i; 

JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint j) 

i = j; 
}
------------------------------------------------------------------------------------


恐怕比较一下volatile和synchronized的不同是最容易解释清楚的。volatile是变量修饰符,而synchronized则作用于一段代码或方法;看如下三句get代码:

int i1;              int geti1() {return i1;}
volatile int i2;  int geti2() {return i2;}
int i3;              synchronized int geti3() {return i3;}
  geti1()得到存储在当前线程中i1的数值。多个线程有多个i1变量拷贝,而且这些i1之间可以互不相同。换句话说,另一个线程可能已经改变了它线程内的i1值,而这个值可以和当前线程中的i1值不相同。事实上,Java有个思想叫“主”内存区域,这里存放了变量目前的“准确值”。每个线程可以有它自己的变量拷贝,而这个变量拷贝值可以和“主”内存区域里存放的不同。因此实际上存在一种可能:“主”内存区域里的i1值是1,线程1里的i1值是2,线程2里的i1值是3——这在线程1和线程2都改变了它们各自的i1值,而且这个改变还没来得及传递给“主”内存区域或其他线程时就会发生。
  而geti2()得到的是“主”内存区域的i2数值。用volatile修饰后的变量不允许有不同于“主”内存区域的变量拷贝。换句话说,一个变量经volatile修饰后在所有线程中必须是同步的;任何线程中改变了它的值,所有其他线程立即获取到了相同的值。理所当然的,volatile修饰的变量存取时比一般变量消耗的资源要多一点,因为线程有它自己的变量拷贝更为高效。
  既然volatile关键字已经实现了线程间数据同步,又要synchronized干什么呢?呵呵,它们之间有两点不同。首先,synchronized获得并释放监视器——如果两个线程使用了同一个对象锁,监视器能强制保证代码块同时只被一个线程所执行——这是众所周知的事实。但是,synchronized也同步内存:事实上,synchronized在“主”内存区域同步整个线程的内存。因此,执行geti3()方法做了如下几步:
1. 线程请求获得监视this对象的对象锁(假设未被锁,否则线程等待直到锁释放)
2. 线程内存的数据被消除,从“主”内存区域中读入(Java虚拟机能优化此步。。。[后面的不知道怎么表达,汗])
3. 代码块被执行
4. 对于变量的任何改变现在可以安全地写到“主”内存区域中(不过geti3()方法不会改变变量值)
5. 线程释放监视this对象的对象锁
  因此volatile只是在线程内存和“主”内存间同步某个变量的值,而synchronized通过锁定和解锁某个监视器同步所有变量的值。显然synchronized要比volatile消耗更多资源。

附英文原文:
What does volatile do?

This is probably best explained by comparing the effects that volatile and synchronized have on a method. volatile is a field modifier, while synchronized modifies code blocks and methods. So we can specify three variations of a simple accessor using those two keywords:

int i1;              int geti1() {return i1;}
volatile int i2;  int geti2() {return i2;}
int i3;              synchronized int geti3() {return i3;}
geti1() accesses the value currently stored in i1 in the current thread. Threads can have local copies of variables, and the data does not have to be the same as the data held in other threads. In particular, another thread may have updated i1 in it’s thread, but the value in the current thread could be different from that updated value. In fact Java has the idea of a “main” memory, and this is the memory that holds the current “correct” value for variables. Threads can have their own copy of data for variables, and the thread copy can be different from the “main” memory. So in fact, it is possible for the “main” memory to have a value of 1 for i1, for thread1 to have a value of 2 for i1 and for thread2 to have a value of 3 for i1 if thread1 and thread2 have both updated i1 but those updated value has not yet been propagated to “main” memory or other threads.

On the other hand, geti2() effectively accesses the value of i2 from “main” memory. A volatile variable is not allowed to have a local copy of a variable that is different from the value currently held in “main” memory. Effectively, a variable declared volatile must have it’s data synchronized across all threads, so that whenever you access or update the variable in any thread, all other threads immediately see the same value. Of course, it is likely that volatile variables have a higher access and update overhead than “plain” variables, since the reason threads can have their own copy of data is for better efficiency.

Well if volatile already synchronizes data across threads, what is synchronized for? Well there are two differences. Firstly synchronized obtains and releases locks on monitors which can force only one thread at a time to execute a code block, if both threads use the same monitor (effectively the same object lock). That’s the fairly well known aspect to synchronized. But synchronized also synchronizes memory. In fact synchronized synchronizes the whole of thread memory with “main” memory. So executing geti3() does the following:

1. The thread acquires the lock on the monitor for object this (assuming the monitor is unlocked, otherwise the thread waits until the monitor is unlocked).
2. The thread memory flushes all its variables, i.e. it has all of its variables effectively read from “main” memory (JVMs can use dirty sets to optimize this so that only “dirty” variables are flushed, but conceptually this is the same. See section 17.9 of the Java language specification).
3. The code block is executed (in this case setting the return value to the current value of i3, which may have just been reset from “main” memory).
4. (Any changes to variables would normally now be written out to “main” memory, but for geti3() we have no changes.)
5. The thread releases the lock on the monitor for object this.

So where volatile only synchronizes the value of one variable between thread memory and “main” memory, synchronized synchronizes the value of all variables between thread memory and “main” memory, and locks and releases a monitor to boot. Clearly synchronized is likely to have more overhead than volatile.

分享到:
评论

相关推荐

    48个关键字

    `synchronized`关键字用于实现同步,确保多个线程对共享资源的互斥访问。 ### 40. this `this`关键字用于引用当前对象,可以在构造器或方法中引用对象的属性或调用对象的方法。 ### 41. throw `throw`关键字用于...

    java中“53”个关键字(含2个保留字)

    42. `synchronized` - 用于线程同步,保证同一时间只有一个线程访问代码块。 43. `this` - 引用当前对象实例。 44. `throw` - 抛出一个异常,中断当前方法执行。 45. `throws` - 方法签名的一部分,声明可能抛出的...

    50个关键字_3个直接量_JAVA的五十个关键词_.zip.zip

    这个压缩包文件"50个关键字_3个直接量_JAVA的五十个关键词_.zip.zip"显然是为了帮助学习者掌握Java中的核心概念。我们将深入探讨这50个关键字以及Java中的3个基本直接量类型。 首先,让我们了解Java的关键字。...

    Java基础标识符关键字数据类型PPT教案学习.pptx

    private、public、protected、final、static、abstract、synchronized、volatile、strictfp、native、transient 等修饰符关键字;try、catch、finally、throw、throws 等异常处理关键字;new、extends、implements、...

    java 关键字查询文档

    50 多个关键字,它们包括但不限于 `abstract`、`assert`、`boolean`、`break`、`byte`、`case`、`catch`、`char`、`class`、`const`(虽然未使用)、`continue`、`default`、`do`、`double`、`else`、`enum`、`...

    Java关键字详细解

    `transient`关键字表明字段不应该序列化。`native`表示方法的实现是在其他地方(如C/C++)完成的,通常与Java的JNI(Java Native Interface)一起使用。 最后,`package`关键字用于组织类和接口,提供命名空间,...

    java51个关键字详解

    Java编程语言中有51个关键字,它们在程序中扮演着至关重要的角色,用来定义类、接口、变量、方法以及控制程序流程。以下是一些主要的关键字及其解释: 1. `abstract`:抽象关键字,用于声明抽象类和抽象方法。抽象...

    Java基础之关键字_Java基础之关键字_源码

    Java的关键字一共51个,包括访问控制修饰符(如public、private、protected)、控制流程关键字(如if、else、for、while)、数据类型关键字(如int、char、boolean)、异常处理关键字(如try、catch、finally)等。...

    50个关键字_3个直接量_JAVA的五十个关键词_

    Java是一种广泛使用的面向对象的编程语言,其语法严谨且丰富,其中包括了50个核心的关键字。这些关键字在Java程序设计中扮演着至关重要的角色,它们帮助开发者定义变量、控制流程、创建类和接口,以及处理异常等。...

    源码关键字统计.rar

    `switch`, `synchronized`, `this`, `throw`, `throws`, `transient`, `try`, `void`, `volatile`, `while`。可以创建一个关键字列表,然后遍历每行代码,检查是否包含这些关键字。 为了提高效率,我们可以使用...

    java中的50个关键字.docx

    #### 四、与修饰符相关的关键字(共12个) 这些关键字用于修改类、方法或变量的可见性和行为特性。 1. **public**:公开的访问级别,任何地方都可以访问。 2. **protected**:受保护的访问级别,同包和子类可以访问...

    java中的关键字大全

    `native`关键字用于声明本地方法,即由非Java语言实现的方法。 ```java public native void nativeMethod(); ``` ##### super `super`关键字用于引用父类的对象。 ```java class Parent { public void sayHello...

    JAVA面向对象基础PPT教案学习.pptx

    * 变量声明格式:[public | protected | private] [static] [final] [transient] [volatile] 变量数据类型 变量名 1 [= 变量初值 ], 变量名 2 [= 变量初值 ], … ; * 访问控制符:public、protected、private * 变量...

    Java关键字

    在Java中,一共有51个关键字(包括保留字),但描述中提到的是48个,可能是因为某些关键字在特定上下文不常用或者被归类到保留字中。下面将详细介绍这些关键字及其用途。 1. **abstract** - 用于声明抽象类或抽象...

    java关键字.pdf

    Java关键字是Java语言中预先定义的、具有特殊意义的单词,它们...此外,文件内容中还出现了一些关于编程环境的内容,如Eclipse和IntelliJ IDEA的快捷键操作,但这些并不是Java语言的关键字,故不在本知识点中详细阐述。

    java语言关键字.pdf

    * native:用来声明一个native方法,这个方法是由外部语言实现的。 * new:用来创建一个对象。 * package:用来声明一个包。 * static:用来定义一个静态变量或方法。 * super:用来访问超类的成员。 * synchronized...

    java关键字

    本文将详细介绍Java中的50个常用关键字,并按照其功能类别进行分类。 #### 数据类型相关关键字 (10个) 1. **byte**: 表示8位带符号的整数类型。 2. **short**: 表示16位带符号的整数类型。 3. **int**: 表示32位带...

    JAVA关键字

    42. **synchronized**:同步关键字,用于线程安全,一次只允许一个线程访问特定代码。 43. **this**:引用当前对象实例。 44. **throw**:抛出一个异常。 45. **throws**:声明方法可能抛出的异常。 46. **...

    Java的关键字与保留字

    在深入探讨Java的关键字与保留字之前,我们首先需明确两个概念:关键字和保留字。在编程语言中,关键字是预定义的具有特殊含义的标识符,它们在编译时被解析器识别并执行特定的功能;而保留字则是语言设计者为未来...

    AS3.0的关键字和保留字

    16. **synchronized**:同步关键字。 17. **throws**:异常抛出关键字。 18. **transient**:临时关键字。 19. **type**:类型关键字。 20. **virtual**:虚拟关键字。 21. **volatile**:易变关键字。 #### 五、...

Global site tag (gtag.js) - Google Analytics