是指:多线程访问了共享数据时,产生了重复的数据和不存在的数据,我们应该避免线程安全问题的产生。
解决线程安全问题的一种方案:使用同步代码块:
synchronized(锁对象){
可能会出现线程安全问题的代码块(访问了共享数据的代码)
}
注意:
1 通过代码块中的锁对象,可以使用任意的对象
2 但是必须保证多个线程中使用的锁对象是同一个
3 锁对象作用:
把同步代码块锁住,只让一个线程在同步代码块中执行。
例如:
1 Object object=new Object();//创建一个锁对象
2 synchronized (锁对象:object){
共享访问的数据
}//同步代码块
同步技术的原理:
使用了一个锁对象,这个锁对象叫同步锁,也叫对象锁,也叫对象监视器。当第一个线程抢到了CPU的执行权,执行Run方法,遇到synchronized代码块这是第一个线程会检查synchronized代码块是否有锁对象发现有,就会获取到锁对象,进入到同步中执行。
当第二个线程抢到了cpu的执行权,执行run方法,遇到synchronized代码块这是会检查synchronized 代码块是否有锁对象,发现没有,就会进入到阻塞状态,会一直等待第一个线程归还锁对象一直到第一个线程执行完同步中的代码,会把锁对象归还给同步代码块,第二个线程才能获取锁对象进入到同步代码块中执行。
总之,同步中的线程,没有执行完毕不会释放锁,同步外的线程没有锁进入不了同步。
解决线程安全问题的第二种方案:
使用同步方法:
1把访问了共享数据的代码抽取出来,放到一个方法中
2 在改方法上添加synchronized修饰符
格式:定义方法的格式
修饰符 synchronized 返回值类型 方法名(参数列表){
可能会出现线程安全问题的代码(访问了共享数据的代码)
}
静态的同步方法:在方法上加上static关键字 它的锁对象是本类的class属性 -->class文件对象(反射)
public staic synchronized void getInstance();
解决线程安全问题的方式:Lock锁 --接口 Lock实现提供了比使用 synchronized方法和语句可获得的更广泛的锁定操作。
该方法可以看到什么时候获取的锁和什么时候释放的锁。
方法:
1 void lock();//获取锁
2 void unlock();//释放锁
java.util.concurrent.locks.Reentrantlock implements lock接口
一般都是使用lock接口的实现类Reentrantlock类
使用步骤:
1 在成员位置创建一个Reentrantlock对象
2 在可能会出现安全问题的代码前调用lock接口中的方法lock获取锁
3 在可能会出现安全问题的代码后调用lock接口中的方法unlock释放锁。
实例: