- synchronized(非公平锁)-重量级锁------偏向锁,轻量级锁、自旋锁
- 1) synchronized方法:在一个对象的方法前加synchronized,使其具有锁,一个线程对其进行调用,只有此线程完成调用后,其他线程才能进行操作。
- 1)当一个线程正在访问一个对象的 synchronized 方法,那么其他线程不能访问该对象的其他 synchronized 方法。这个原因很简单,因为一个对象只有一把锁,当一个线程获取了该对象的锁之后,其他线程无法获取该对象的锁,所以无法访问该对象的其他synchronized方法。
- 2)当一个线程正在访问一个对象的 synchronized 方法,那么其他线程能访问该对象的非 synchronized 方法。这个原因很简单,访问非 synchronized 方法不需要获得该对象的锁,假如一个方法没用 synchronized 关键字修饰,说明它不会使用到临界资源,那么其他线程是可以访问这个方法的,
- 3)如果一个线程 A 需要访问对象 object1 的 synchronized 方法 fun1,另外一个线程 B 需要访问对象 object2 的 synchronized 方法 fun1,即使 object1 和 object2 是同一类型),也不会产生线程安全问题,因为他们访问的是不同的对象,所以不存在互斥问题。
- 2) synchronized 同步块:
- 当在某个线程中执行这段代码块,该线程会获取对象lock的锁,从而使得其他线程无法同时访问该代码块。其中,lock 可以是 this,代表获取当前对象的锁,也可以是类中的一个属性,代表获取该属性的锁。特别地, 实例同步方法 与 synchronized(this)同步块 是互斥的,因为它们锁的是同一个对象。但与 synchronized(非this)同步块 是异步的,因为它们锁的是不同对象。
- 实现同步的方法:1)利用同步代码块实现;2)利用同步方法实现;
- 1)synchronized(锁对象任意,不可以用匿名对象,不代表同一个锁){需要完整执行的代码块};
- 2)使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的;
- 非静态同步函数的锁是:this(实例对象)
- 静态的同步函数的锁是:该类的字节码对象.class;
- 3) class 对象锁
- 特别地,每个类也会有一个锁,静态的 synchronized方法 就是以Class对象作为锁。另外,它可以用来控制对 static 数据成员 (static 数据成员不专属于任何一个对象,是类成员) 的并发访问。并且,如果一个线程执行一个对象的非static synchronized 方法,另外一个线程需要执行这个对象所属类的 static synchronized 方法,也不会发生互斥现象。因为访问 static synchronized 方法占用的是类锁,而访问非 static synchronized 方法占用的是对象锁,所以不存在互斥现象。
- 1) synchronized方法:在一个对象的方法前加synchronized,使其具有锁,一个线程对其进行调用,只有此线程完成调用后,其他线程才能进行操作。
- synchronized可重用锁:一般地,当某个线程请求一个由其他线程持有的锁时,发出请求的线程就会阻塞。然而,由于 Java 的内置锁是可重入的,因此如果某个线程试图获得一个已经由它自己持有的锁时,那么这个请求就会成功。可重入锁最大的作用是避免死锁。
- Lock 和 Synchronized 的选择
- (1). Lock是一个接口,是JDK层面的实现;而synchronized是Java中的关键字,是Java的内置特性,是JVM层面的实现;
- (2). synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
- (3). Lock 可以让等待锁的线程响应中断,而使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
- (4). 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到;
- (5). Lock可以提高多个线程进行读操作的效率。
- 在性能上来说,如果竞争资源不激烈,两者的性能是差不多的。而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择
- 使用 volatile 关键字的场景
- synchronized 关键字是防止多个线程同时执行一段代码,那么就会很影响程序执行效率;而 volatile 关键字在某些情况下性能要优于 synchronized,但是要注意 volatile 关键字是无法替代 synchronized 关键字的,因为 volatile 关键字无法保证操作的原子性。通常来说,使用 volatile 必须具备以下两个条件:
- 1)对变量的写操作不依赖于当前值;
- 2)该变量没有包含在具有其他变量的不变式中。
- 实际上,这些条件表明,可以被写入 volatile 变量的这些有效值 独立于任何程序的状态,包括变量的当前状态。事实上,上面的两个条件就是保证对 该volatile变量 的操作是原子操作,这样才能保证使用 volatile关键字 的程序在并发时能够正确执行。
- 特别地,关键字 volatile 主要使用的场合是:在多线程环境下及时感知共享变量的修改,并使得其他线程可以立即得到变量的最新值。
- Java内存模型 规定所有的变量都是存在主存当中(类似于前面说的物理内存),每个线程都有自己的工作内存(类似于前面的高速缓存)。线程对变量的所有操作都必须在工作内存中进行,而不能直接对主存进行操作,并且每个线程不能访问其他线程的工作内存。缓冲同步问题
- synchronized 关键字是防止多个线程同时执行一段代码,那么就会很影响程序执行效率;而 volatile 关键字在某些情况下性能要优于 synchronized,但是要注意 volatile 关键字是无法替代 synchronized 关键字的,因为 volatile 关键字无法保证操作的原子性。通常来说,使用 volatile 必须具备以下两个条件:
- Atiomic类的使用:单独使用保证原子性,连续多Atiomic方法调用不能保证原子性
Java并发编程面试
最新推荐文章于 2019-07-04 00:44:17 发布