synchronized的锁对象的特点

JAVA中synchronized关键字能够作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。假如再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。synchronizedvoidf() { /* body */ }void f() { synchronized(this) { /* body */} }完全等价的。

synchronized(class)很特别,它会让另一个线程在任何需要获取class做为monitor的地方等待。class与this作为不同的监视器可以同时使用,不存在一个线程获取了class,另一个线程就不能获取该class的一切实例。

  1. 对于实例同步方法,锁是当前实例对象。
  2. 对于静态同步方法,锁是当前对象的Class对象。
  3. 对于同步方法块,锁是Synchonized括号里配置的对象。
class与this的几种情况:
synchronized(class)
synchronized(this)

线程各自获取monitor,不会有等待。

synchronized(this)
synchronized(this)

如果不同线程监视同一个实例对象,就会等待;如果不同的实例,不会等待。

synchronized(class)
synchronized(class)

如果不同线程监视同一个实例或者不同的实例对象,都会等待。



单例模式,有“懒汉式”和“饿汉式”两种。

懒汉式

单例类的实例在第一次被引用时候才被初始化。

public class Singleton {  
    private static Singleton instance=null;  
     
    private Singleton() {  
         
    }  
     
    public static Singleton getInstance(){  
        if (instance == null) {  
            instance = new Singleton();  
        }  
         
        return instance;  
    }  
}

饿汉式

单例类的实例在加载的时候就被初始化。

public class Singleton {  
    private static Singleton instance = new Singleton();  
     
    private Singleton() {  
         
    }  
     
    public static Singleton getInstance(){  
        return instance;  
    }  
}

在单线程程序中,上面两种形式基本可以满足要求了,但是在多线程环境下,单例类就有可能会失效,这个时候就要对其加锁了,来确保线程安全。

对线程加锁用的synchronized关键字,这个关键字的用法主要也分为两种:

一种是加在方法名之前,形如:synchronized methodeName(params){……};

二是声明同步块,形如:synchronized(this){……};

下面是对懒汉式单例类加上线程同步的实现:

同步方法:

public class Singleton {  
    private static Singleton instance=null;  
     
    private Singleton() {  
         
    }  
     
    public synchronized static Singleton getInstance(){  
        if (instance == null) {  
            instance = new Singleton();  
        }  
         
        return instance;  
    }  
}

这种方式效率比较低,性能不是太好,不过也可以用,因为是对整个方法加上了线程同步,其实只要在new的时候考虑线程同步就行了,这种方法不推荐使用。

同步代码块:

public class Singleton {  
    private static Singleton instance;  
    private final static Object syncLock = new Object();  
     
    private Singleton() {  
         
    }  
     
    public static Singleton getInstance(){  
        if (instance == null) {  
            synchronized (syncLock) {  
                if (instance == null) {  
                    instance = new Singleton();  
                }  
            }  
        }  
         
        return instance;  
    }  
}

synchronized同步块括号中的锁定对象是采用的一个无关的Object类实例,而不是采用this,因为getInstance是一个静态方法,在它内部不能使用未静态的或者未实例的类对象,因此也可以用下面的方法来实现:

public class Singleton {  
    private static Singleton instance;  
     
    private Singleton() {  
         
    }  
     
    public static Singleton getInstance(){  
        if (instance == null) {  
            synchronized (Singleton.class) {  
                if (instance == null) {  
                    instance = new Singleton();  
                }  
            }  
        }  
         
        return instance;  
    }  
}

同步代码块的这两种方式都是比较推荐使用的,我就一直在项目中使用,有问题以后可以再改进。


### Java中`synchronized`关键字的特点 #### 1. **原子性** `synchronized`能够确保一个操作或者一组操作具有原子性,即这些操作要么完全执行完毕,要么根本不被执行,在此期间不会被其他线程中断。这种特性对于保护共享资源非常重要[^2]。 #### 2. **可见性** 当一个线程释放了由`synchronized`所持有的之后,它对共享变量所做的任何修改都会立即变得对其他线程可见。这解决了多线程环境下由于缓存而导致的数据不一致性问题。 #### 3. **有序性** 通过使用`synchronized`,可以有效避免因处理器优化或编译器重排序而引发的潜在问题。它强制保证程序按照代码书写的顺序来执行,从而维护了逻辑上的正确性和预期的行为。 #### 4. **独占性** 在任意给定的时间点上,最多只允许有一个线程进入并执行被标记为`synchronized`的方法或代码块。这一特点有助于防止多个并发线程同时访问临界区,进而规避数据竞争条件的发生[^1]。 #### 5. **可重入性** 如果某个线程已经持有了某把,则该线程再次尝试获取同一把时会成功而不必等待。这是因为在内部实现层面支持所谓的“重入计数”,每调用一次加就增加计数值;相应地每次解则减少这个值直到最终彻底释放为止[^3]。 ### 使用场景 - 当存在多个线程可能同时读写同一个对象的状态时; - 需要协调不同线程之间的动作次序以完成特定任务的时候; - 对于某些关键业务逻辑必须保持其完整性不可分割的情况下适用。 ```java public class Counter { private int count; public synchronized void increment() { // 方法级别同步 this.count++; } public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); Runnable task = () -> { for (int i = 0; i < 1000; ++i) { counter.increment(); } }; Thread t1 = new Thread(task); Thread t2 = new Thread(task); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(counter.getCount()); // 输出应该是2000 } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值