java 线程个人总结

[b]关于原子[/b]
嗯,为什么要加锁?相信有点基础的童鞋都很清楚。在多线程情况下调用方法主要会出现两类问题 --原子性和非原子性!那他们各自会在神马情况下出现捏?

举一个《thinking in java》第四版中的例子。有一个EvenGenerator类,它的next()方法用来生成偶数。如下:

public class EvenGenerator {

private int currentValue = 0;
private boolean cancled = false;

public int next() {
++currentValue; //危险!
++currentValue;
return currentValue;
}

public boolean isCancled() {
return cancled;
}
public void cancle() {
cancled = true;
}
}


另外有一个EvenChecker类,用来不断地检验EvenGenerator的next()方法产生的是不是一个偶数,它实现了Runnable接口。


public class EvenChecker implements Runnable {

private EvenGenerator generator;

public EvenChecker(EvenGenerator generator) {
this.generator = generator;
}

@Override
public void run() {
int nextValue;
while(!generator.isCancled()) {
nextValue = generator.next();
if(nextValue % 2 != 0) {
System.out.println(nextValue + "不是一个偶数!");
generator.cancle();
}
}
}
}


然后创建两个EvenChecker来并发地对同一个EvenGenerator对象产生的数字进行检验。


public class Test {

public static void main(String[] args) {
EvenGenerator generator = new EvenGenerator();
Thread t1 = new Thread(new EvenChecker(generator));
Thread t2 = new Thread(new EvenChecker(generator));

t1.start();
t2.start();
}
}


显然,在一般情况下,EvenGenerator的next()方法产生的数字肯定是一个偶数,因为在方法体里进行两次”++currentValue”的操作。但是运行这个程序,输出的结果竟然像下面这样(并不是每次都是这个一样的结果,但是程序总会因这样的情况而终止):


849701不是一个偶数!


错误出在哪里呢?程序中有“危险”注释的哪一行便可能引发潜在的错误。因为很可能某个线程在执行完这一行只进行了一次递增之后,CPU时间片被另外一个线程夺去,于是就生产出了奇数。

原子性(atomicity)
具有原子性的操作被称为原子操作。原子操作在操作完毕之前不会线程调度器中断。在Java中,对除了long和double之外的基本类型的简单操作都具有原子性。简单操作就是赋值或者return。比如”a = 1;”和 “return a;”这样的操作都具有原子性。但是在Java中,上面例子中的类似”++currentValue;”这样的操作不具有原子性,所以如果add方法不是同步的就会出现难以预料的结果。在某些JVM中”++currentValue;”可能要经过这样四个步骤:
1.从内存得到currentValue的值
2.第一次+currentValue
3.第二次+currentValue
4.把currentValue写回内存
上面会出现奇数的情况就是第一次+currentValue完成的时候,还没来得及往内存中写数据。CPU的时间片被另一个线程占用,当那个线程使用完CPU切换回来的时候再来运行+currentValue,就会出现奇数了!

解决以上问题的方法无疑就是同步

[b]关于synchronized[/b]
1.方法上加synchronized 是给整个类加锁。synchronized(Object){}是给object对象加锁。相对而言各有各的用处,但是,不到迫不得已坚决不用synchronized加锁!

步的代价:首先,同步化的方法有些额外的成本。进入同步化方法的程序会查询锁等性能上的损耗。其次,同步化方法会强制线程队列排队等着执行方法。最后,同步化很可能会导致死锁!!!!!!!!!!!!!!!!!!

[color=red]同步的死锁[/color]
在java中,死锁是一件很恐怖的事情!因为java根本没有处理死锁的机制,他甚至不会知道死锁的发生!

下面来看一下可以如何导致死锁
head firs java 中的说法

两个线程和两个对象
线程A foo
线程B bar
1.线程A进入对foo对象设定同步化的方法
2.线程B进入对bar对象设定同步化的方法,线程B接着尝试要进入A正在执行的方法。所以B一直等着。
3.线程A醒来尝试调用线程B正在执行的方法,但拿不到钥匙,所以只好等着
A一直等着B的bar钥匙,B却也在等着A的foo钥匙。两个线程就这样僵持着!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章