在开发中,对同一资源的访问需要考虑同步的问题,但是同步的使用需要慎重,过多的使用同步往往会降低性能,甚至有可能发生死锁,其实同步只是在复杂的情况下不得已而为之的一种办法。
在使用同步的时候要考虑两个问题:1.是不是一定要使用同步 2.被访问的资源是否属于原子型的
在一些特定的情况下,多线程访问同一个资源是不需要同步的,比如读取操作,针对方法内局部变量的写操作也不需要同步,同步的关键在于类变量的访问操作,一旦设置了类变量,那么就要考虑同步。根据banq的资料,整理如下:
public class Test {
private int state;
private volatile long stateLong;
private byte[] states = null;
private String stateStrs = null;
private final Object stateObject = null;
private HashMap map = new HashMap;
private Hashtable hashTable = new Hashtable;
public void setState(int state) {
this.state = this.state + state;
}
...
}
在上面的Test类中,有5个类变量,分别代表5中不同的类变量:
1.state的类型是int,int属于Java原始型变量。原始变量的操作访问都是原子型的(long和double除外),所以对原始变量的操作访问都是现成安全的,不需要实现同步。
2.对long和double操作访问可以加上volatile。多线程工作中有准内存和工作内存之分,在JVM中有一个主内存,专门负责所有线程共享数据,每个线程有它自己私有的共组内存,volatile变量表示保证他必须与主内存保持一致,实际上是变量的同步。注意并不是所有的虚拟机都支持volatile。。。
3.数组属于object,所以对数组的访问必须实现同步。
4.使用final,阻止对这个类进行集成拓展的可能,并且可以提高JVM效率
5.使用HashMap或Hashtable时也要注意同步问题。在HashMap中加入新对象引用时,要使用同步方法;而Hashtable已经实现了内部同步,操作时久不需要同步了。同样List和Vector也是这样的处理方式。
在同步的时候,要避免发生死锁。避免死锁没有一个万全之策,只有自己小心应付。以下的办法对避免死锁有所帮助:
1.缩小同步范围
2.如果使用wait,可以指定毫秒数,在一定时间后结束等待,避免死锁。
3.使用性能调试工具可以检测死锁现象,如Borland的Optimizeit Profiler。