Synchronized 有几种用法?

本文详细介绍了Java中Synchronized关键字的五种使用场景,包括同步普通方法、同步静态方法、同步类、同步this实例以及同步对象实例,深入解析每种用法的特点及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们都知道 Synchronized 是线程安全同步用的,大部分程序可能只会用到同步方法上面。其实 Synchronized 可以用到更多的场合,栈长列举了以下几个用法。

1、同步普通方法

这个也是我们用得最多的,只要涉及线程安全,上来就给方法来个同步锁。这种方法使用虽然最简单,但是只能作用在单例上面,如果不是单例,同步方法锁将失效。

/**
 * 用在普通方法
 */
private synchronized void synchronizedMethod() {
    System.out.println("synchronizedMethod");
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

此时,同一个实例只有一个线程能获取锁进入这个方法。

2、同步静态方法

同步静态方法,不管你有多少个类实例,同时只有一个线程能获取锁进入这个方法。

/**
 * 用在静态方法
 */
private synchronized static void synchronizedStaticMethod() {
    System.out.println("synchronizedStaticMethod");
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

同步静态方法是类级别的锁,一旦任何一个线程进入这个方法,其他所有线程将无法访问这个类的任何同步类锁的方法。

3、同步类

下面提供了两种同步类的方法,锁住效果和同步静态方法一样,都是类级别的锁,同时只有一个线程能访问带有同步类锁的方法。

/**
 * 用在类
 */
private void synchronizedClass() {
    synchronized (TestSynchronized.class) {
        System.out.println("synchronizedClass");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

/**
 * 用在类
 */
private void synchronizedGetClass() {
    synchronized (this.getClass()) {
        System.out.println("synchronizedGetClass");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

这里的两种用法是同步块的用法,这里表示只有获取到这个类锁才能进入这个代码块。

4、同步this实例

这也是同步块的用法,表示锁住整个当前对象实例,只有获取到这个实例的锁才能进入这个方法。

/**
 * 用在this
 */
private void synchronizedThis() {
    synchronized (this) {
        System.out.println("synchronizedThis");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

用法和同步普通方法锁一样,都是锁住整个当前实例。

5、同步对象实例

这也是同步块的用法,和上面的锁住当前实例一样,这里表示锁住整个 LOCK 对象实例,只有获取到这个 LOCK 实例的锁才能进入这个方法。

/**
 * 用在对象
 */
private void synchronizedInstance() {
    synchronized (LOCK) {
        System.out.println("synchronizedInstance");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

另外,类锁与实例锁不相互阻塞,但相同的类锁,相同的当前实例锁,相同的对象锁会相互阻塞。

关于 Synchronized 的几种用法栈长就介绍到这里了,如果你还知道其他的用法,欢迎留言。

### 线程概念 线程,即轻量级进程(LWP: Light Weight Process),是程序执行流的最小单元。一个线程是一个进程内的顺序执行流。同一别的多个线程共享一块内存空间一组系统资源,而每个线程拥有自己的堆栈用于程序执行时的数据存储。由于线程间的切换开销较小,因此被称作轻负荷进程。在一个进程中可以存在多个线程来并发处理不同的任务[^2]。 ### Java线程的主要状态及其描述 #### 1. 新建 (NEW) 当线程对象被创建后,但尚未启动之前处于新建状态。此时该线程还没有开始运行任何操作,在调用`start()`方法前一直保持这种状态[^1]。 #### 2. 可运行 (RUNNABLE) 一旦调用了线程实例上的`start()`方法,线程就进入了可运行状态。这意味着JVM现在可以在适当的时候安排此线程去执行其体内的逻辑;然而,“可运行”并不意味着它当前正在CPU上实际执行——也可能是因为调度原因暂时未被执行。在这个状态下,线程可能正忙于计算或是等待I/O操作完成等事件的发生[^3]。 #### 3. 阻塞 (BLOCKED) 如果某个线程试图获取已被另一个活动中的线程占用的对象监视器(例如通过`synchronized`关键字保护的方法代码块),那么这个请求失败并将使原尝试加的那个线程进入阻塞状态直到目标变得可用为止。一旦获得了所需的定条件满足,线程就会返回到之前的可运行状态继续前进。 #### 4. 等待 (WAITING) 当线程显式地调用了诸如`Object.wait()`, `Thread.join()` 或者`LockSupport.park()`这样的API之后会陷入无限期休眠并转入等待状态。除非接收到特定的通知信号唤醒它们,否则这些线程将一直处于停滞不前的状态中。比如对于`wait()`来说就是需要其他线程调用同一个对象上的`notify()/notifyAll()`方法来进行激活。 #### 5. 超时期等待 (TIMED_WAITING) 这是指那些设置了固定时限暂停下来的线程所处的一种特殊形式下的等待状况。典型的情况包括但不限于: - 使用带参数版本的`Thread.sleep(long millis)`函数指定毫秒数作为延迟间隔; - 带有超时选项的各种`wait(timeout)`,`join(timeout)` `parkNanos/timeUnit` API调用。 经过设定好的时间段过后即使没有任何外部干预也会自动苏醒过来转回至可运行队列里排队等候进一步指令[^4]。 #### 6. 终止 (TERMINATED) 无论正常结束还是因发生错误异常提前退出,只要完成了自身的使命或者无法再向前推进下去了,线程最终都将步入终止阶段不再参与后续的任务分配与执行过程之中。 ```java // 示例:展示如何创建并启动一个新的线程 public class Example { public static void main(String[] args){ Thread thread = new Thread(() -> System.out.println("这是一个新线程")); thread.start(); // 启动线程使其从 NEW 进入 RUNNABLE 状态 } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值