一.java中共享数据分为以下5类
1.不可变,即被final修饰如java.lang.String类的对象就是不可变对象,调用replace()等方法,都不会影响原来的值,只会返回一个新的字符串对象,Long等包装类型也是不可变
2.绝对线程安全.javaAPI中标注是线程安全的类,大多不是绝对安全的,例如java.util.Vector
中get(),size(),remove()方法都被synchronized修饰但两个方法在一起并不能保证安全
for(int i=0;i<vector.size()){
vector.remove();
}
两个不同的线程执行此循环的时候不能保证安全,可能会报异常
3.相对线程安全:是通常意义上的线程安全,保证了对这个对象单独的操作是安全的,但是连续调用还需要额外的手段,如上 4.线程兼容:对象本身不安全,可以在调用端采取手段,保证安全,平时所说的线程不安全的,大多是这一情况,如ArrayList
5.线程对立,无论是否在调用端采取手段,都不能保证安全,一个线程对立的例子是Thread类的suspend()和resume()方法 如果两个线程同时持有一个线程对象,一个尝试中断线程,一个恢复线程,如果并发进行,不管调度者是否进行了同步,目标线程都存在死锁风险,
二.线程安全的实现方法
1.互斥同步,即同一时刻只能有一个线程访问共享数据.java实现互斥同步的最基本手段synchronized关键字
synchronized是重量级的操作,必须用才用,比较影响性能.
除了synchronized还可以使用java.util.concurrent包中的重入锁(ReentranLock)实现同步,
多了几个高级功能:a.等待可中断(等待的线程可以中途放弃等待,该做其他的)
b.可以实现公平锁(即按照申请锁的顺序来获得锁)synchronized是非公平的.默认非公平,可以通过代Boolean值的构造函数要求使用公平锁
c.锁可以绑定多个条件
能完成需求的情况下,优先使用synchronized
2.非阻塞同步,先操作,没有其他线程争用共享数据,操作成功,有的话,采取补救措施(常见的是不断的重试,直到成功)
3.无同步方案:不涉及共享数据,可重入代码和线程本地存储(Hibernate中将session绑定当前线程)(一个请求对应一个线程)
java语言中如果一个变量被多个线程访问,可以使用volatitle关键字修饰,如果是本线程独享的使用java.lang.ThreadLocal类实现本地存储功能