synchronized作用,线程安全与非线程安全,锁,对象锁

一、线程安全与非线程安全

        线程安全: 获得的实例变量的值是经过同步处理的,不会出现脏读的现象。

        非线程安全: 多个线程同时对同一个对象中的同一个实例变量进行操作时会出现值被更改,值不同步的情况(也就是“脏读”),进而影响程序的执行流程。

       “非线程安全”的问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在“非线程安全”的问题。

二、synchronized 同步方法

        格式:synchronized 修饰符 类型 方法名(){}

1.多个对象多个锁

        关键字synchronized取得的锁是对象锁,而不是把一段代码或方法当作锁,这就说明了:如果多个线程访问同一个类的不同的实例的相同名称的同步方法,代码是以异步的方式运行的,因为JVM创建了多个锁。

2.锁重入

        当一个线程得到一个对象锁后,再次请求此对象锁时是可以得到该对象的锁的。这也证明在一个synchronized 方法/块的内部调用本类的其他的synchronized 方法/块时,是永远可以得到锁的。

3.出现异常,锁自动释放

        当一个线程执行的代码出现异常时,其所持有的锁会自动释放。这样可以避免出现死锁。

4.同步不具有继承性

        子类重写父类中的同步方法时,synchronized的作用不会被继承。运行是以异步方式运行的。如果想要同步运行,需要在重写后的方法前边加 synchronized。

三、synchronized 同步语句块

        使用synchronized 声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个长时间的任务,那么B线程则必须等待比较长的时间。这时如果使用synchronized 同步语句块可以很好地解决这一问题。

1.一半同步,一半异步

        在synchronized块中的代码是同步执行,不在synchronized块中的就是异步执行的。

2.synchronized 代码块间的同步性

        在使用synchronized(this)代码块时要注意:当一个线程访问对象的一个synchronized(this)同步代码块时,其他线程对同一个对象中的所有其他synchronized(this)同步代码块的访问将被阻塞。

3.synchronized(this) 代码块锁定

        synchronized(this) 代码块锁定的是当前对象。

4.synchronized() 代码块将任意对象作为对象监视器

        多个线程调用同一个对象的不同名称的synchronized 同步方法或synchronized(this)同步代码块时,调用的效果是按顺序执行,也就是同步的,阻塞的。
        Java 还支持对“任意对象”作为“对象监视器”来实现同步的功能。这个“任意对象”大多是实例变量及方法的参数,使用格式为synchronized(非this对象)。

作用:
        在多个线程持有“对象监视器”(非this对象)为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(非 this对象)同步代码块中的代码。

优点:
        如果在一个类中有很多个synchronized方法,这时虽然能实现同步,但会阻塞,会影响运行效率;但如果使用同步代码块锁非this对象,则synchronized(非this)代码块中的程序与同步方法是异步的,不与其他锁this同步方法争抢this锁,可以大大提高运行效率。

synchronized(非this 对象x) 是将x对象本身作为“对象监视器”,所以:
        1)当多个线程同时执行synchronized(x){}同步代码块时呈同步效果。
        2)当其它线程执行x对象中的synchronized同步方法(同一个类中的其他同步方法)时呈同步效果。
        3)当其他线程执行x对象方法里面的synchronized(this)代码块时 呈同步效果。

四、静态同步synchronized方法 与 synchronized(class) 同步

        关键字synchronized 应用在static静态方法上,作用是:对当前的*.java文件对应的Class 类进行持锁。这个锁和对象锁不是同一个锁,Class锁可以对类的所有对象实例起作用。
        同步synchronized(class)代码块的作用其实和 synchronized static 方法的作用一样

五、注意 synchronized(String 对象)

        在JVM中具有String 常量池缓存的功能,下边代码运行结果为 true。

public class Demo{
	public static void main(String[] args){
		String a = "a";
		String b = "a";
		System.out.println(a == b);
	}
}

        将synchronized(string)同步块与String联合使用时,要注意常量池带来的例外。可以使用 new Object() 实例化一个Object对象,但它并不放入缓存中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值