千家信息网

synchronized加锁this和class的区别是什么

发表于:2024-11-17 作者:千家信息网编辑
千家信息网最后更新 2024年11月17日,本篇内容介绍了"synchronized加锁this和class的区别是什么"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔
千家信息网最后更新 2024年11月17日synchronized加锁this和class的区别是什么

本篇内容介绍了"synchronized加锁this和class的区别是什么"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

synchronized 是 Java 语言中处理并发问题的一种常用手段,它也被我们亲切的称之为"Java 内置锁",由此可见其地位之高。然而 synchronized 却有着多种用法,当它修饰不同对象时,其意义也是不同的,下面我们一起来看。

synchronized 用法

synchronized 可以用来修饰普通方法、静态方法和代码块。

① 修饰普通方法

/** * synchronized 修饰普通方法 */public synchronized void method() {    // .......}

当 synchronized 修饰普通方法时,被修饰的方法被称为同步方法,其作用范围是整个方法,作用的对象是调用这个方法的对象。

② 修饰静态方法

/** * synchronized 修饰静态方法 */public static synchronized void staticMethod() {    // .......}

当 synchronized 修饰静态的方法时,其作用的范围是整个方法,作用对象是调用这个类的所有对象。

③ 修饰代码块

为了减少锁的粒度,我们可以选择在一个方法中的某个部分使用 synchronized 来修饰(一段代码块),从而实现对一个方法中的部分代码进行加锁,实现代码如下:

public void classMethod() throws InterruptedException {    // 前置代码...        // 加锁代码    synchronized (SynchronizedExample.class) {        // ......    }        // 后置代码...}

以上代码在执行时,被修饰的代码块称为同步语句块,其作用范围是大括号"{}"括起来的代码块,作用的对象是调用这个代码块的对象。

但以上代码,除了可以加锁 class 之外,还可以加锁 this,具体示例如下:

public void classMethod() throws InterruptedException {    // 前置处理代码...    synchronized (this) {        // ......    }    // 后置处理代码...}

那问题来了,使用 synchronized 加锁 this 和 class 的区别是什么?不都是加锁同一个类吗?

答案还真不是,加锁 this 和 class 区别还是很大的。下面我们通过以下 4 个示例,来看二者之间的区别。

1.加锁 class 共享一个类实例

首先,我们创建 5 个线程,调用同一个对象下 synchronized 加锁的 class 代码,具体示例如下:

import java.util.Date;import java.util.concurrent.TimeUnit;public class SynchronizedExample {    public static void main(String[] args) {        // 创建当前类实例        final SynchronizedExample example = new SynchronizedExample();        // 创建 5 个线程执行任务        for (int i = 0; i < 5; i++) {            new Thread(new Runnable() {                @Override                public void run() {                    try {                        // 调用 synchronized 修饰的 class 方法                        example.classMethod();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }).start();        }    }    /**     * synchronized 修饰的 class 方法     * @throws InterruptedException     */    public void classMethod() throws InterruptedException {        synchronized (SynchronizedExample.class) {            System.out.println(String.format("当前执行线程:%s,执行时间:%s",                    Thread.currentThread().getName(), new Date()));            TimeUnit.SECONDS.sleep(1);        }    }}

以上程序的执行结果如下:

从上述结果可以看出,这 5 个线程共享的是同一把锁。

2.加锁 class 创建多个实例

接下来,我们创建 5 个线程,调用不同对象下 synchronized 加锁的 class 代码,具体示例如下:

import java.util.Date;import java.util.concurrent.TimeUnit;public class SynchronizedExample {    public static void main(String[] args) {        // 创建 5 个线程执行任务        for (int i = 0; i < 5; i++) {            new Thread(new Runnable() {                @Override                public void run() {                    try {                        // 创建类实例                        SynchronizedExample example = new SynchronizedExample();                        // 调用 synchronized 修饰的 class 方法                        example.classMethod();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }).start();        }    }        /**     * synchronized 修饰的 class 方法     * @throws InterruptedException     */    public void classMethod() throws InterruptedException {        synchronized (SynchronizedExample.class) {            System.out.println(String.format("当前执行线程:%s,执行时间:%s",                    Thread.currentThread().getName(), new Date()));            TimeUnit.SECONDS.sleep(1);        }    }}

以上程序的执行结果如下:

从上述结果可以看出,虽然是不同的对象,但它们使用的仍然是同一把锁。

3.加锁 this 共享一个类实例

接下来,我们创建 5 个线程,调用 synchronized 加锁 this 的示例。首先我们这 5 个线程调用同一个对象的加锁方法,示例代码如下:

import java.util.Date;import java.util.concurrent.TimeUnit;public class SynchronizedExample {    public static void main(String[] args) {        // 创建当前类实例        final SynchronizedExample example = new SynchronizedExample();        // 创建 5 个线程执行任务        for (int i = 0; i < 5; i++) {            new Thread(new Runnable() {                @Override                public void run() {                    try {                        // 调用 synchronized 修饰的 this 方法                        example.thisMethod();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }).start();        }    }        /**     * synchronized 修饰的 this 方法     * @throws InterruptedException     */    public void thisMethod() throws InterruptedException {        synchronized (this) {            System.out.println(String.format("当前执行线程:%s,执行时间:%s",                    Thread.currentThread().getName(), new Date()));            TimeUnit.SECONDS.sleep(1);        }    }}

以上程序的执行结果如下:

从上述结果可以看出,以上线程使用的都是同一把锁。

4.加锁 this 创建多个类实例

最后一个示例最为特殊,我们使用 synchronized 加锁 this,让这 5 个线程调用各自创建对象的方法,具体示例如下:

import java.util.Date;import java.util.concurrent.TimeUnit;public class SynchronizedExample {    public static void main(String[] args) {        // 创建 5 个线程执行任务        for (int i = 0; i < 5; i++) {            new Thread(new Runnable() {                @Override                public void run() {                    try {                        // 创建(多个)类实例                        SynchronizedExample example = new SynchronizedExample();                        // 调用 synchronized 修饰的 this 方法                        example.thisMethod();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }).start();        }    }        /**     * synchronized 修饰的 this 方法     * @throws InterruptedException     */    public void thisMethod() throws InterruptedException {        synchronized (this) {            System.out.println(String.format("当前执行线程:%s,执行时间:%s",                    Thread.currentThread().getName(), new Date()));            TimeUnit.SECONDS.sleep(1);        }    }}

以上程序的执行结果如下:

从上述结果可以看出,当使用 synchronized 加锁 this 时,如果线程调用的不是同一个对象,那么这些线程之间使用的锁都是自己独立的锁,这个结果就和 synchronized 加锁 class 的结果完全不同了。

"synchronized加锁this和class的区别是什么"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

0