非线程安全:在多个线程对同一个对象中的实例进行并发访问时发生,产生的后果即为脏读。
线程安全:获得的实例变量的值是经过同步处理的,不会出现脏读现象。
非线程安全问题存在于实例变量中,即共享的变量 ,但若是方法内部的私有变量,则不存在非线程安全问题。这是因为方法内部的变量是私有的特性造成的。
如果多个线程同时访问一个对象中的实例变量,则有可能出现非线程安全问题。
解决方法:在方法前加关键字synchronized即可。在两个线程访问同一个对象中的同步方法时一定是线程安全的。
多个对象多个锁。关键字synchronized取得的锁都是对象锁,那个线程先访问带synchronized关键字的方法,那个线程就持有该方法所属对象的锁Lock,那么其他线程就只能处于等待状态,前提是多个线程访问的是同一个对象。
Service service = new Service(); Thread t1 = new Thread(service); Thread t2 = new Thread(service); t1.start(); t2.start();但若是多个线程访问多个对象,则jvm就会创建多个锁,则运行结果就是异步的。
Service service1 = new Service(); Service service2 = new Service(); Thread t1 = new Thread(service1); Thread t2 = new Thread(service2); t1.start(); t2.start();若A线程先持有object对象的Lock锁,B线程可以以异步的方式调用object对象中的非synchronized方法。
若A线程先持有object对象的Lock锁,B线程如果要调用object对象中的synchronized方法则需等待,也就是同步。
脏读:在读取实例变量时,此值已经被其他线程更改过了。
synchronized锁重入:在使用synchronized关键字时,当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的锁的。即在一个synchronized方法/块的内部调用本类的其他synchronized方法/块时,是永远可以得到锁的。
public class Service{ public synchronized methodA(){ methodB(); } public synchronized methodB(){ } }线程会同步调用methodA--methodB的顺序。
可重入锁:自己可以再次获取自己的内部锁。
可重入锁也支持在父子类继承的环境中。当存在父子类继承关系是,子类是完全可以通过可重入锁的方式调用父类的同步方法。
当一个线程执行的代码出现异常时,其所持有的锁会自动释放。
同步不具有继承性。所以override父类的synchronized方法仍需要加上synchronized关键字。
来源:oschina
链接:https://my.oschina.net/u/2518655/blog/625740