线程安全问题
- 什么是线程安全
多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能访问知道该线程读取完后,其他线程才可以使用出现数据不一致或者数据污染 - 线程不安全
线程不安全就是不提供数据的访问保护,有可能出现多个线程更改数据造成所得到的数据时脏数据(引用自http://blog.csdn.net/ghevinn/article/details/37764791/)
线程安全是面向同一个资源的时候才有讨论价值,当时不同的资源的时候就没有讨论的价值了,比如一个银行账户对其进行查看余额和存入金额的操作的时候就需要讨论线程安全的问题
Synchronized
- 当有两个线程同时对资源进行操作的时候,如果没有上锁的话,这个线程对共享变量的操作还没有结束并更新到主内存中取,其他的线程依然可能调用到共享的变量,这就会造成混乱。把这种现象叫做此线程对其他线程是不可见的。
- 当有所的状况下,先操作资源的线程要执行完成后,才会释放锁,这个时候其他的上了synchronized的方法或其他才能继续操作资源数据。
- synchronized的作用
1、互斥
正因为有了互斥,从而实现了synchronized块线程执行的原子性:
即一个线程在执行该synchronized块的时候,其他线程是不会进来的
除非当前线程释放了资源锁。
2、内存可见
正因为可以实现内存可见,所以可以通过主内存实现线程通信。 - 注意
有synchronized的,一定可以实现内存可见。
但反过来说,是不是没有synchronized,就一定内存不可见呢?
不一定。对于JVM而言,通常情况下,一个线程对共享的变量的更新一般会及时同步到主内存,对其他线程而言,通常是可见的。
但这不是绝对的,只有加了synchronized,才能从根本上保证内存的可见。
public synchronized void saveMoney(){
balance=1000;
}
public synchronized int readMoney(){
return balance;
}
public void saveMoney2(){
synchronized (this) {
balance=1000;
public class Tool {
private Object object=new Object();
private List<String> list=new ArrayList<>();
/**
* 1、使用synchronized修饰类方法的时候,现在上锁的资源是类,而不是这个类的具体的某一个对象
* 2、如果synchronized上锁的资源是类,对该类的实例对象是没有影响的.
* 即你不要认为你对类上了锁,就对这个类的实例对象上了锁
* */
public synchronized void add(){
for(int a=0;a<10;a++){
System.out.println("a = "+a);
Thread.yield();
}
}
public void save(){
synchronized (this) {
for(int b=0;b<10;b++){
System.out.println("b = "+b);
Thread.yield();
}
}
}
public void f1(){
synchronized (this) {
for(int a=0;a<10;a++){
System.out.println("a = "+a);
Thread.yield();
}
}
}
/**
* 即便是Dog继承Animal,
* 对于线程锁而言,它只关注上锁的具体的资源,而不关注其继承关系。
* */
public void f2(){
synchronized (this) {
for(int b=0;b<10;b++){
System.out.println("b = "+b);
Thread.yield();
}
}
}
}
- 对于线程锁而言,它只关注上锁的具体的资源,而不关注其继承关系
- 上锁的范围?
上锁的范围不是指synchronized代码块的范围,而是指synchronized对应的上锁的对象(资源)