”非线程安全“会在多个线程对同一个对象中的实例对象进行并发访问时发生,产生的后果就是”脏读“,也就是取到的数据其实是被更改过的。而”线程安全“就是以获得的实例变量的值是经过同步处理的,不会出现脏读的现象。
#1.方法内的变量为线程安全
方法中的变量不存在非线程安全问题,这是方法内部的变量是私有的特性造成的。
#2.实例变量非线程安全
如果多个线程共同访问1个对象中的实例变量,需要在方法前添加关键字 synchronized 。这样就不会出现非线程安全问题。
#3.多个对象多个锁
1 | Hbbq h1 = new Hbbq(); |
从以上代码可以看出,我们创建了两个 Hbbq 的实例对象。这样的话,加了 synchronized 的方法,便会产生两个锁,结果就不会是同步,而是以异步的方式运行的。
如果多个线程访问多个对象,JVM就会创建多个锁,就像上面的示例一样。同步的单词是 synchronized ,异步的单词是 asynchronized。
#4.synchronized方法与锁对象
当两个线程同时访问一个对象的不同的两个方法:
第一次实验的是一个同步的方法,一个不同步的方法
第二次实验的是两个都是同步的方法
代码我就不贴了,直接写结论:
1)A线程先持有object对象的lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法。
2)A线程先持有object对象的lock锁,B线程如果在这时调用object对象中的synchronized类型的方法则需等待,也就是同步。
#5.脏读
出现脏读的原因就是不同步。解决的方法就是加上同步synchronized关键字。
这里注意一点,当一个线程A调用了对象里加入synchronized关键字的X方法时,那么A线程就获得了X的方法锁,更准确的讲,是获得了这个对象的锁,其他线程必须等待A线程执行完毕才可以调用X方法,但其他线程可以随意调用其他的非synchronized同步方法。所以,需要把set 和 get 方法都加上 synchronized 关键字,这样的话就可以避免出现脏读。
#6.synchronized锁重入
可重入锁的概念是:自己可以再次获取自己的内部锁。这样就可以调用 synchronized方法 里的 synchronized方法。
可重入锁也支持在父子类继承的环境中。在子类中调用父类里的变量,值也可以同步。
#7.出现异常,锁自动释放
就是说,当一个线程执行的代码出现异常时,那么这个线程所持有的锁会被自动释放,然后别的线程就可以继续去调用这个方法了。
#8.同步不具有继承性
当一个子类继承一个父类时,子类重写父类的 synchronized 方法,却没有加关键字 synchronized,这样就会造成非线程安全(异步)。由此可以看出,同步不能继承。