不同方面浅浅认识一下 Synchronized
Java中的synchronized关键字是一种用于线程同步的机制,它可以确保同一时间只有一个线程能够访问共享资源。本篇博客将从synchronized的基本用法、synchronized锁的对象、synchronized的可重入性、synchronized的锁粒度、synchronized与锁优化等多个方面来深入介绍Java中synchronized关键字的使用。
一、synchronized的基本用法
synchronized关键字可以应用于方法和代码块上,以下是synchronized的基本用法示例:
1.1 修饰方法
synchronized可以用于修饰方法,使得在调用该方法时,只有一个线程能够执行该方法,其他线程需要等待。
public synchronized void syncMethod() { // synchronized方法体 } 复制代码
1.2 修饰代码块
synchronized还可以用于修饰代码块,只有当线程获取到该代码块的锁时才能进入执行,其他线程需要等待。
public void syncBlock() { synchronized (this) { // synchronized代码块 } } 复制代码
二、synchronized锁的对象
synchronized锁的对象可以是类的实例对象、类对象、任意对象等。以下是synchronized锁的对象示例:
2.1 类的实例对象
当synchronized锁的对象是类的实例对象时,不同的线程对同一个实例对象的同步方法或同步代码块的访问将会被阻塞,因为它们都是使用同一个对象锁。
public synchronized void syncMethod() { // synchronized方法体 } public void syncBlock() { synchronized (this) { // synchronized代码块 } } 复制代码
2.2 类对象
当synchronized锁的对象是类对象时,不同的线程对同一个类的同步方法或同步代码块的访问将会被阻塞,因为它们都是使用同一个类锁。
public static synchronized void syncMethod() { // synchronized方法体 } public void syncBlock() { synchronized (SynchronizedDemo.class) { // synchronized代码块 } } 复制代码
2.3 任意对象
当synchronized锁的对象是任意对象时,不同的线程对同一个对象的同步方法或同步代码块的访问将会被阻塞,因为它们都是使用同一个对象锁。
public synchronized void syncMethod() { // synchronized方法体 } public void syncBlock() { Object lock = new Object(); synchronized (lock) { // synchronized代码块 } } 复制代码
三、synchronized的可重入性
synchronized具有可重入性,即一个线程已经获得了一个对象的锁,再次请求该对象的锁时仍然可以获得该锁。
public synchronized void syncMethod() { syncMethod2(); // synchronized方法体 } 复制代码
在上面的代码中,syncMethod2()方法也是一个synchronized方法,当syncMethod()方法调用syncMethod2()方法时,它仍然可以获取到该对象的锁,因为锁是可重入的。
四、synchronized的锁粒度
synchronized锁的粒度大小是需要考虑的一个问题,粒度过大会导致性能下降,粒度过小又可能导致死锁。以下是synchronized锁的粒度示例:
4.1 对象锁
对象锁的粒度最细,它只锁定对象中的一个方法或代码块。
public synchronized void syncMethod() { // synchronized方法体 } public void syncBlock() { synchronized (this) { // synchronized代码块 } } 复制代码
4.2 类锁
类锁的粒度比对象锁大,它锁定的是整个类的同步方法或同步代码块。
public static synchronized void syncMethod() { // synchronized方法体 } public void syncBlock() { synchronized (SynchronizedDemo.class) { // synchronized代码块 } } 复制代码
五、synchronized与锁优化
Java中的synchronized关键字在使用时需要考虑锁的粒度和性能问题,同时也有一些锁优化的技巧可以使用,以下是synchronized与锁优化的示例:
5.1 减小锁粒度
如果使用了对象锁,可以将锁的粒度减小到对象的某个属性上,以减少锁的粒度,从而提高程序的并发性。
public void syncBlock() { synchronized (lock) { // synchronized代码块 } } public void syncBlock2() { synchronized (lock.getProperty()) { // synchronized代码块 } } 复制代码
5.2 双重检查锁定
双重检查锁定技术可以减少锁的粒度,提高程序的并发性。
public class Singleton { private volatile static Singleton instance; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } 复制代码
在以上代码中,通过双重检查锁定的方式,可以确保Singleton实例只被创建一次,并且提高了程序的并发性能。
5.3 锁消除
在一些情况下,编译器会自动消除一些不必要的锁,以提高程序的并发性能。
public void syncMethod() { StringBuilder sb = new StringBuilder(); sb.append("a").append("b").append("c"); // sb对象没有被其他线程共享,可以消除锁 synchronized (sb) { // synchronized代码块 } } 复制代码
以上代码中,由于sb对象没有被其他线程共享,因此编译器可以自动消除synchronized。
六、synchronized的局限性和替代方案
synchronized虽然是Java中一个非常重要的同步机制,但它也有一些局限性和替代方案。
6.1 局限性
- synchronized只能保证单个线程的同步,无法保证多个线程之间的协作;
- synchronized在多线程并发访问下会导致性能下降;
- synchronized在死锁等异常情况下可能导致程序出现问题。
6.2 替代方案
Java中有许多替代方案可以代替synchronized实现同步,以下是一些常用的替代方案:
- Lock:Lock是Java中提供的一个新的同步机制,它可以替代synchronized实现线程同步,具有更好的扩展性和性能;
- Atomic:Atomic提供了一些原子操作,可以实现一些线程安全的操作;
- ConcurrentHashMap:ConcurrentHashMap是Java中线程安全的Map,可以实现高并发访问;
- Semaphore:Semaphore是一种计数信号量,可以用来控制对公共资源的访问。
七、总结
synchronized是Java中非常重要的同步机制,它可以保证多个线程之间的安全协作,但在使用时需要考虑锁的粒度和性能问题,同时也有一些锁优化的技巧可以使用。
除了synchronized之外,Java中还有许多替代方案可以实现线程同步,包括Lock、Atomic、ConcurrentHashMap等。在实际应用中,需要根据具体的场景选择适合的同步机制来保证程序的正确性和性能。会在后续讲解不同锁结构