- 首先来看几个问题
ArrayList和Vector的区别在哪里?
HashMap和HashTable区别在哪里?
StringBuilder和StringBuffer区别在哪里?
张口即答,区别在于前者是非线程安全的,后者是线程是线程安全的。
那么,到底什么叫线程安全?什么叫线程不安全?线程安全不安全的原因是什么?怎么实现线程安全?线程安全和非线程安全有
什么区别?分别在什么情况下使用?
一、线程安全
是指你的代码所在的进程中有多个线程同时运行,而这些线程可能会同时运行这段代码,如果每次运行的代码结
果和单线程运行的结果是一样的,而且其他变量的值和预期的也是一样的,那么就是线程安全的。
或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,
也就是说我们不用考虑同步的问题。
线程安全问题都是由全局变量及静态变量引起的。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行
写操作,一般都需要考虑线程同步,否则就可能影响线程安全。
二、非线程安全
是不提供代码数据访问保护,可能出现多个线程先后访问更改数据造成所得的数据是脏数据。*(脏数据是表示一个数据已经
被修改,但是还没有保存或进一步的处理。例如你操作数据库修改某一字段内容,在你修改了但还没commit时,另一线程在读取这
数据,他读取的就是你修改前的数据,但事实上你已经修改了,这就是脏数据了。)*在多个线程同时访问同一个对象时会发生数据
错误 不完整等情况时 那就是线程不安全,不会发生上续错误时是线程安全的,一般采用锁机制。
三、线程安全出现的根本原因
存在两个或者两个以上的线程对象共享同一个资源;
多线程操作共享资源代码有多个语句。
存在竞争的线程不安全,不存在竞争的线程就是安全的
四、怎么实现线程安全
同步代码块、同步方法
synchronized关键字,就是用来控制线程同步的,保证我们的线程在多线程环境下,不被多个线程同时执行,确保我们数据的完
整性,使用方法一般是加在方法上。
public class ThreadDemo {
int count = 0; // 记录方法的命中次数
public synchronized void threadMethod(int j) {
count++ ;
int i = 1;
j = j + i;
}
}
这样就可以确保我们的线程同步了,同时这里需要注意一个大家平时忽略的问题,首先synchronized锁的是括号里的对象,而不是代码,其次,对于非静态的synchronized方法,锁的是对象本身也就是this。
当synchronized锁住一个对象之后,别的线程如果想要获取锁对象,那么就必须等这个线程执行完释放锁对象之后才可以,否则一直处于等待状态。
注意点:虽然加synchronized关键字,可以让我们的线程变得安全,但是我们在用的时候,也要注意缩小synchronized的使用范围,如果随意使用时很影响程序的性能,别的对象想拿到锁,结果你没用锁还一直把锁占用,这样就有点浪费资源。
Lock锁机制, 通过创建Lock对象,采用lock()加锁,unlock()解锁,来保护指定的代码块
五、分别在什么情况下使用
线程安全是多线程操作同一个对象不会有问题;
非线程安全是指多线程操作同一个对象可能会出现问题;
线程安全会导致性能的降低。
如果是多个线程操作同一个对象,那么使用线程安全的Vector;否则,就使用效率更高的ArrayList。
PS(非线程安全并非不安全)
非线程安全并不是多线程环境下就不能使用。