2010年7月14日
摘要: class文件之常量池分析
当JVM运行Java程序的时候,它会加载对应的class文件,并提取class文件中的信息存放在JVM开辟出来的方法区 内存中。那么这个class文件里面到底有些什么内容呢?
一、class文件内容概述
class文件是由8bits的字节流组成,全部字节构成了15个有意义的项目。这些项目之间没有任何无意义的字节,因...
阅读全文
posted @
2010-12-07 17:51 QZZF 阅读(234) |
评论 (0) |
编辑 收藏
volatile:具有 synchronized
的可见性特性,但是不具备原子特性.这就是说线程能
够自动发现 volatile 变量的最新值.
使用volatile原则:
对变量的写操作不依赖于当前值。
该变量没有包含在具有其他变量的不变式中
package zhang.feng.concurrent.atomic;
public class VolatileTest {
private String str="";
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
private void doit(){
new Thread(new Runnable(){
public void run() {
setStr("没有写入主存中");
System.out.println("====");
}
},"THREAD_ONE").start();
new Thread(new Runnable(){
public void run() {
String str=getStr();
System.out.println(str);
}
},"THREAD_TWO").start();
}
public static void main(String[] args){
VolatileTest vt=new VolatileTest();
vt.doit();
}
}
上面的例子,如果不使用volatile变量,可能出现的情况是(出现几率很小),THREAD_ONE线程在setStr()后,THREAD_TWO执行了getStr(),但是由于并没有将数据写入主存中,而此时getStr()获得的数据将是过时数据.
解决的方式,通过lock(开销比较大),使用volatile变量(如上).
正确使用 volatile 的模式
1.状态标志
volatile boolean shutdownRequested;
public void shutdown() { shutdownRequested = true; }
public void doWork() {
while (!shutdownRequested) {
// do stuff
}
}
可能在另一个线程中调用shutdown(),那么使用volatile可以保证shutdownRequested可见性,所以不需要使用lock来实现数据同步.
该模式特征:只有一种状态的转换.
2.一次性安全发布
public class BackgroundFloobleLoader {
public volatile Flooble theFlooble;
public void initInBackground() {
// do lots of stuff
theFlooble = new Flooble(); // this is the only write to theFlooble
}
}
public class SomeOtherClass {
public void doWork() {
while (true) {
// do some stuff
// use the Flooble, but only if it is ready
if (floobleLoader.theFlooble != null)
doSomething(floobleLoader.theFlooble);
}
}
}
在如果initInBackground(写入)和doWork(读取)在不同线程同时执行时,那么可能获得的更新后的Flooble对象也可能是未更新前的,而是用volatile可以保证是读取到更新后的对象.
该模式的一个必要条件是:被发布的对象必须是线程安全的,或者是有效的不可变对象(有效不可变意味着对象的状态在发布之后永远不会被修改)。
3.独立观察
public class UserManager {
public volatile String lastUser;
public boolean authenticate(String user, String password) {
boolean valid = passwordIsValid(user, password);
if (valid) {
User u = new User();
activeUsers.add(u);
lastUser = user;
}
return valid;
}
}
该模式可以用于收集最近一次登录信息,并提交其他应用处理.
4.“volatile bean” 模式
@ThreadSafe
public class Person {
private volatile String firstName;
private volatile String lastName;
private volatile int age;
public String getFirstName() { return firstName; }
public String getLastName() { return lastName; }
public int getAge() { return age; }
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setAge(int age) {
this.age = age;
}
}
结束语
与锁相比,Volatile 变量是一种非常简单但同时又非常脆弱的同步机制,它在某些情况下将提供优于锁的性能和伸缩性。如果严格遵循
volatile 的使用条件 —— 即变量真正独立于其他变量和自己以前的值 —— 在某些情况下可以使用 volatile
代替 synchronized
来简化代码。然而,使用 volatile
的代码往往比使用锁的代码更加容易出错。本文介绍的模式涵盖了可以使用 volatile
代替 synchronized
的最常见的一些用例。遵循这些模式(注意使用时不要超过各自的限制)可以帮助您安全地实现大多数用例,使用 volatile 变量获得更佳性能。
使用CountDownLatch可以保证指定线程数的顺利完成,如下:
public class CountDownLatchTest {
static int N=5;//指定需要等待完成的线程数
static CountDownLatch cdl=new CountDownLatch(N);
static List list=new ArrayList();
public static void main(String[] args) {
for(int i=0;i<N;i++){
new Thread(new countDownLatchRunnable(i),"Thread_"+i).start();
}
try {
cdl.await();//等待在cdl.countDown()之前进行的操作都顺利完成
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("LIST_1 size["+list.size()+"]");//希望获得是size>=5
}
static class countDownLatchRunnable implements Runnable{
int num;
countDownLatchRunnable(int num){
this.num=num;
}
@Override
public void run() {
doWork();//而在cdl.countDown()之前的操作,则在调用await()时,则会等待该部分操作完成
cdl.countDown();
list.add(num);//如果在cdl.countDown()后添加操作,那么在cdl.await()处并不会等待该部分操作完成,而是会有竞争
}
private void doWork(){
//执行其他工作
list.add(num);
}
}
}
如果不使用CountDownLatch,那么在main线程和其他线程都是处于竞争关系,最后的size结果可能也是随机存在的