synchronized、volatile 、Lock

synchronized 有什么作用?原理是什么?

synchronized 是多线程中的一种同步机制,能够有效避免多线程执行过程中出现脏数据的问题。

使用同步锁之后,在同一个时间内只能被同一个线程执行,只有这个线程执行完了才能被另一个线程执行。有点类似于火车站中的排队机制。

synchronized 有默认的锁,在普通方法中是以 Object.this 作为默认的锁,而在静态方法中则以 Object.class 作为默认的锁。当然我们也可以在同步代码块中指定某个的对象作为同步锁。

volatile 有什么作用?能保证线程安全吗?

被 volatile 修饰的变量,会保证不同线程对该变量的可见性,即一个线程改变了该变量的值,这个新值对于其他线程来讲都是可见的。

但即使如此,volatile 仍然不能不保证线程安全的问题,例如 i++ 在被多个线程同时执行,i++ 其实分为三个步骤:读值、计算、写值,假设这些线程都已经读取到 i 的值并且进行得出了结果 1,但是在都没有开始写入内存的情况下,后面有一个线程先改变了 i 的值,然后这个新值对于后面的线程是可见的,但是后面的线程已经不需要读取这个值了,因为后面的线程对 i + 1 已经计算完成了,这个线程要做的是将 1 赋值给 i,而不会再获取一次 i 的值再进行计算。

volatile 不能保证多线程并发下的数据安全,所以想要线程安全只能使用同步锁。

synchronized 和 Lock 有什么区别?Lock 的效率为什么比 synchronized 要高?开发中该如何抉择?

这两种方式都能实现同步锁,只不过实现方式的不同,synchronized 是 Java 的关键字,而 Lock 是 Java 中的一个接口类。

synchronized 是自动加锁和释放锁,而 Lock 需要手动加锁和释放锁(lock、unlock)。所以 Lock 效率要比 synchronized 要高。

在实际开发中,虽然 Lock 效率比较高,但是一般情况下我们仍然选用 synchronized,因为在并发量比较少的情况下,使用 synchronized 和 Lock 从效率上并无太大差异。

synchronized关键字用在方法和代码块上的区别

synchronized关键字可应用在方法级别(粗粒度锁)或者是代码块级别(细粒度锁)。
synchronized 关键字是不能继承的

同步方法和同步块:

同步方法就是在方法前加关键字synchronized,然后被同步的方法一次只能有一个线程进入,其他线程等待。
而同步块则是在方法内部使用大括号使得一个代码块得到同步。同步块会有一个同步的”目标“,使得同步块更加灵活一些(同步块可以通过”目标“决定需要锁定的对象)。一般情况下,如果此”目标“为this,那么同步方法和同步块没有太大的区别。

非静态和静态的区别主要在于(以同步方法为例):非静态的同步方法是锁定类的实例的,而静态的同步方法是锁定类的;
也就是说,对于非静态的同步方法,在同一时刻,一个类的一个实例中,只有一个线程能进入同步的方法。但是对于多个实例,每一个实例的一个线程都可以进入同一同步的方法。

同步方法直接在方法上加synchronized实现加锁,同步代码块则在方法内部加锁,很明显,同步方法锁的范围比较大,而同步代码块范围要小点,一般同步的范围越大,性能就越差,一般需要加锁进行同步的时候,肯定是范围越小越好,这样性能更好。

public class SynchronizedTest{
	
	Person p = new Person("lin", 15);
	
	public synchronized void say(){//相当于锁住this,效果和say3()一样,只要多个线程同时访问同一个SynchronizedTest实例(相当于this),就会发生不能同时访问此方法
		System.out.println(p.getName());
	}
	
	public void say2(){
		synchronized(p){//相当于锁住p,只要多个线程同时访问此代码块且是同一个p,就会发生不能同时访问此代码块锁住
			System.out.println(p.getName());
		}
	}
	
	public void say3(){
		synchronized(this){//锁住this,效果和say()一样,只要多个线程同时访问同一个SynchronizedTest实例(this),就会发生不能同时访问此代码块
			System.out.println(p.getName());
		}
	}
}

synchronized关键字以及对象锁和类锁的区别
1 无论是修饰方法还是修饰代码块都是 对象锁,当一个线程访问一个带synchronized方法时,由于对象锁的存在,所有加synchronized的方法都不能被访问(前提是在多个线程调用的是同一个对象实例中的方法)
2 无论是修饰静态方法还是锁定某个对象,都是 类锁.一个class其中的静态方法和静态变量在内存中只会加载和初始化一份,所以,一旦一个静态的方法被申明为synchronized,此类的所有的实例化对象在调用该方法时,共用同一把锁,称之为类锁。

放入对象和Class的区别

锁住的对象不同:成员方法锁住的实例对象,静态方法锁住的事Class
访问控制不同:如果所著的是实例,只会针对同一个对象方法进行同步访问,多线程访问同一个对象的synchronized代码块是串行的,访问不同对象是并行的。如果锁住的是类,多线程访问的不管是同一对象has不同对象的synchronized代码块都是串行的

  • synchronized关键字不能继承。也就是说子类重写了父类中用synchronized修饰的方法,子类的方法仍然不是同步的。
  • 定义接口方法时,不能使用synchronized关键字。
  • 构造方法不能使用synchronized关键字,但是可以使用synchronized代码块。

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值