synchronized 关键字浅析
synchronized 关键字概述
- Java 平台中的任何一个对象都有唯一一个与之关联的锁。这种锁被称为监视器或者内部锁。
- 内部锁是一种排他锁,它能够保障原子性、可见性和有序性。内部锁是通过 synchronized 关键字实现的。
- synchronized 关键字可以用来修饰方法以及代码块。
- synchronized 关键字修饰的方法就被称为同步方法。
- synchronized 修饰的静态方法就被称为静态同步方法。
- synchronized 修饰的实例方法就被称为实例同步方法。同步方法的整个方法体就是一个临界区。
synchronized 关键字修饰的代码块被称为同步块,其语法如下所示:
synchronized(锁句柄){
}
注意: 作为锁句柄的变量通常采用 private final 修饰,如:private final Object lock = new Object();
synchronized 实例方法和 synchronized 代码块
假设有如下 synchronized 实例方法。
synchronized void method() {
}
这跟下面将方法体用 synchronized 代码块包围起来是等效的。
void method() {
synchronized (this) {
}
}
也就是说,synchronized 实例方法是使用 this 的锁来执行线程的互斥处理的。
synchronized 静态方法和 synchronized 代码块
synchronized 关键字线程八锁
- (1)
- (2)
- (3)
- (4)
- (5)
- (6)
- (7)
- (8)
- (9)
- (10)
- (11)
- (12)
两个普通同步方法,两个 Number 对象?不同步
public class Test {
public static void main(String[] args) {
Number number1 = new Number();
Number number2 = new Number();
new Thread(() -> {
number1.getOne();
}).start();
new Thread(() -> {
number2.getTwo();
}).start();
}
}
class Number {
public synchronized void getOne() {
System.out.println("one");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
public synchronized void getTwo() {
System.out.println("two");
}
}
两个静态同步方法,两个 Number 对象?同步
public class Test {
public static void main(String[] args) {
Number number1 = new Number();
Number number2 = new Number();
new Thread(() -> {
number1.getOne();
}).start();
new Thread(() -> {
number2.getTwo();
}).start();
}
}
class Number {
public static synchronized void getOne() {
System.out.println("one");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
public static synchronized void getTwo() {
System.out.println("two");
}
}
一个静态同步方法,一个非静态同步方法,两个 Number 对象?不同步
public class Test {
public static void main(String[] args) {
Number number1 = new Number();
Number number2 = new Number();
new Thread(() -> {
number1.getOne();
}).start();
new Thread(() -> {
number2.getTwo();
}).start();
}
}
class Number {
public static synchronized void getOne() {
System.out.println("one");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
public synchronized void getTwo() {
System.out.println("two");
}
}
两个静态同步方法,一个 Number 对象?同步
public class Test {
public static void main(String[] args) {
Number number = new Number();
new Thread(() -> {
number.getOne();
}).start();
new Thread(() -> {
number.getTwo();
}).start();
}
}
class Number {
public static synchronized void getOne() {
System.out.println("one");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
public static synchronized void getTwo() {
System.out.println("two");
}
}
两个普通同步方法,一个 Number 对象?同步
public class Test {
public static void main(String[] args) {
Number number = new Number();
new Thread(() -> {
number.getOne();
}).start();
new Thread(() -> {
number.getTwo();
}).start();
}
}
class Number {
public synchronized void getOne() {
System.out.println("one");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
public synchronized void getTwo() {
System.out.println("two");
}
}
一个静态同步方法,一个非静态同步方法,一个 Number 对象?不同步
public class Test {
public static void main(String[] args) {
Number number = new Number();
new Thread(() -> {
number.getOne();
}).start();
new Thread(() -> {
number.getTwo();
}).start();
}
}
class Number {
public static synchronized void getOne() {
System.out.println("one");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
public synchronized void getTwo() {
System.out.println("two");
}
}
一个(静态 or 非静态)同步方法,一个(静态 or 非静态)非同步方法,一个 Number 对象?不同步
public class Test {
public static void main(String[] args) {
Number number = new Number();
new Thread(() -> {
number.getOne();
}).start();
new Thread(() -> {
number.getTwo();
}).start();
}
}
class Number {
public synchronized void getOne() {
System.out.println("one");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
public void getTwo() {
System.out.println("two");
}
}
一个(静态 or 非静态)同步方法,一个(静态 or 非静态)非同步方法,两个 Number 对象?不同步
public class Test {
public static void main(String[] args) {
Number number1 = new Number();
Number number2 = new Number();
new Thread(() -> {
number1.getOne();
}).start();
new Thread(() -> {
number2.getTwo();
}).start();
}
}
class Number {
public synchronized void getOne() {
System.out.println("one");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
public void getTwo() {
System.out.println("two");
}
}
synchronized 关键字的特点
- 可重入性,当一个线程再次请求自己持有对象锁的临界资源时,这种情况属于重入锁,请求将会成功。
从互斥锁的设计上来说,当一个线程试图操作一个由其他线程持有的对象锁的临界资源时,将会处于阻塞状态,但当一个线程再次请求自己持有对象锁的临界资源时,这种情况属于重入锁,请求将会成功,在 Java 中 synchronized 是基于原子性的内部锁机制,是可重入的,因此在一个线程调用 synchronized 方法的同时在其方法体内部调用该对象另一个 synchronized 方法,也就是说一个线程得到一个对象锁后再次请求该对象锁,是允许的,这就是 synchronized 的可重入性。
- 自动释放锁,当代码段执行结束或出现异常后会自动释放对监视器的锁定。
- 非公平锁,在等待获取锁的过程中不可被中断。
- 互斥性,被 synchronized 修饰的方法同时只能由一个线程执行。
synchronized 关键字的使用
普通方法和代码块中使用 this 是同一个监视器(锁),即某个具体调用该代码的对象。
静态方法和代码块中使用该类的 class 对象是同一个监视器,任何该类的对象调用该段代码时都是在争夺同一个监视器的锁定。
注意:作为锁句柄的变量通常采用 private final 修饰,如:private final Object lock = new Object();
public class SynchronizedTest implements Runnable {
private static int i = 0;
public static synchronized void increase() {
i++;
}
@Override
public void run() {
for (int j = 0; j < 10000000; j++) {
increase();
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new SynchronizedTest());
Thread t2 = new Thread(new SynchronizedTest());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
public class SynchronizedTest {
public synchronized void method1() {
System.out.println("Method 1 start");
try {
System.out.println("Method 1 execute");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 1 end");
}
public synchronized void method2() {
System.out.println("Method 2 start");
try {
System.out.println("Method 2 execute");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 2 end");
}
public static void main(String[] args) {
SynchronizedTest test = new SynchronizedTest();
new Thread(test::method1).start();
new Thread(test::method2).start();
}
}
public class SynchronizedTest {
public synchronized void method1() {
System.out.println("Method 1 start");
try {
System.out.println("Method 1 execute");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 1 end");
}
public void method2() {
System.out.println("Method 2 start");
try {
System.out.println("Method 2 execute");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 2 end");
}
public static void main(String[] args) {
SynchronizedTest test = new SynchronizedTest();
new Thread(test::method1).start();
new Thread(test::method2).start();
}
}
public class SynchronizedTest {
public synchronized void method1() {
System.out.println("Method 1 start");
try {
System.out.println("Method 1 execute");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 1 end");
}
public void method2() {
System.out.println("Method 2 start");
try {
System.out.println("Method 2 execute");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 2 end");
}
public static void main(String[] args) {
SynchronizedTest test1 = new SynchronizedTest();
SynchronizedTest test2 = new SynchronizedTest();
new Thread(test1::method1).start();
new Thread(test2::method2).start();
}
}
public class SynchronizedTest implements Runnable {
private static final SynchronizedTest instance = new SynchronizedTest();
private static int i = 0;
@Override
public void run() {
synchronized (instance) {
for (int j = 0; j < 10000000; j++) {
i++;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
//this锁的是当前实例对象
synchronized (this) {
for (int j = 0; j < 1000000; j++) {
i++;
}
}
//class锁的是当前类对象
synchronized (AccountingSync.class) {
for (int j = 0; j < 1000000; j++) {
i++;
}
}
synchronized 关键字常见面试题
- Java 中有哪些锁?synchronized 与 Lock 有哪些区别?什么是公平锁和非公平锁?他们的底层怎么实现的?
- 谈谈 synchronized 关键字的理解?synchronized 的实现,锁的升级过程。synchronized 什么情况下会释放锁?
- synchronized 能否锁静态方法,synchronized 修饰同一个类的两个静态方法同步吗,为什么。
- 如果一个对象有多个方法加了 synchronized,那么该对象有几把锁。【一把锁】
- synchronized 分别修饰在实例方法上和静态方法上,多线程并发时是否会竞争锁?
- synchronized 修饰在方法上和代码块上有什么区别,底层是怎么实现的?
- Lock 接口的实现类 ReentrantLock 和 synchronized 有什么区别?ReentrantReadWriteLock 呢?
- 说下 synchronized 的用法,说下 JDK 对 synchronized 的优化?
- synchronized 关键字的作用、原理、锁升级、锁粗化、锁消除、偏向锁、轻量级锁、重量级锁。
- 为什么要用 synchronized?原理?效率?
- synchronized 是可重入锁么。synchronized 为什么说他比较重。
- volatile、synchronized 的用法,比如 synchronized 在静态方法和普通方法上面时,能否同时进入?
- volatile、synchronized、Lock 的区别?
- 说说你用到 volatile 和 synchronized 的一些场景。(说了个双重校验单例模式 DCL)
- synchronized 的底层实现原理以及和 volatile 的区别?他们能保证原子性吗?能保证可见性吗?
- CAS 和 synchronized 有什么区别?都用 synchronized 不行么?
- 说一下 Java 的内存模型?
- 说一下 volatile 关键字?他的原理是什么?volatile 是线程安全的吗?
- 说一下 volatile 和 synchronized 这两个关键字的区别?
synchronized 关键字参考资料
本博客所有文章除特别声明外,均采用
CC BY-NC-SA 4.0
许可协议,转载请注明出处!



