线程同步
之前我们说过,java中允许多线程并发执行,那么当多个线程改变一个共享的内存量时,可能会存在冲突,此时就要进行线程同步的处理了。
synchronzied锁
synchronzied可以修饰方法和代码块,synchronized不能继承。
同步方法
由于java对象的内置一个互斥锁,当使用该关键字修饰方法时,这个方法称为同步方法。在调用该方法时需要先获得锁,否则会处于阻塞状态。
synchronized 与static synchronized区别
synchronized的范围是某个类的对象,防止多个线程同时访问同一个类对象的synchronized代码块。
static synchronized地方范围是某个类,防止多个线程多个实例同时访问这个类的synchronized代码块。它可以对类的所有对象实例起作用。
同步代码块
synchronized关键字修饰的语句块为同步代码块。 被该关键字修饰的语句块会自动被加上内置锁,从而实现同步如 synchronized(object){ }。
当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
ReentrantLock重入锁
ReenreantLock类的常用方法有:
ReentrantLock() : 创建一个ReentrantLock实例
lock() : 获得锁,进入同步代码块
unlock() : 释放锁,出同步代码块
tryLock();尝试拿到锁,如果有锁就拿到,没有拿到不会阻塞,返回false。
synchronized和ReentrantLock的区别
(1)ReentrantLock需要手动上锁和解锁,而synchronized自动上锁。且Lock使用中必须释放锁,否则容易造成死锁。
(2)Lock可以尝试获得锁,线程可以不用一直等待;而synchronized中,假设A线程获得锁,B线程等待。如果A线程阻塞,B线程会一直等待。
(3)Lock可判断锁的状态,而synchronized不可。
(4)Lock中可以自己控制锁是否公平,而且,默认的是非公平锁;synchronized为非公平锁。
公平锁:按等待获取锁的线程的等待时间进行获取,等待时间长的具有优先获取锁权利。
volatile
volatile关键字保证可见性。当一个共享变量被volatile修饰的时候,他会保证变量被修改之后立马在内存中更新,另一线程在取值的时候需要去内存中读取新的值。
volatile关键字提供了一种免锁机制,每次使用时需要重新计算而不是从寄存器中获取。
volatile不会提供任何原子操作,无法保证原子性。它也不能用来修饰final类型的变量