synchronized到底锁住的是谁?

我们使用synchronized关键字是用来实现线程同步的,当多个线程同时去争抢同一个资源的时候在资源上边加一个synchronized关键字,能够使得线程排队去完成操作。
synchronized到底锁定的是什么资源?

修饰方法
    非静态方法 ,锁定的是方法的调用者。
    静态方法,锁定的是类。
修饰代码块锁定的是传入的对象

一、修饰方法

非静态方法 ,锁定的是方法的调用者

1.不加synchronized关键字,看多线程怎么执行

public class Test {
    public static void main(String[] args) {
        Data data = new Data();
        Thread t1 = new Thread(){
            @Override
            public void run(){
                data.fun1();
            }
        };
        t1.start();
        //休眠一秒钟以后再去启动2线程
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread t2 = new Thread(){
            @Override
            public void run(){
                data.fun2();
            }
        };
        t2.start();
    }
}
class Data{
    public void fun1(){
        //休眠3秒以后再进行输出
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("1....");
    }
    public void fun2(){
        System.out.println("2....");
    }
}

输出:首先会在1s钟以后输出 2…,然后2秒钟以后输出1…
在这里插入图片描述
在这里插入图片描述

2.加上synchronized关键字,看多线程怎么执行

public class Test {
    public static void main(String[] args) {
        Data data = new Data();
        Thread t1 = new Thread(){
            @Override
            public void run(){
                data.fun1();
            }
        };
        t1.start();
        //休眠一秒钟以后再去启动2线程
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Thread t2 = new Thread(){
            @Override
            public void run(){
                data.fun2();
            }
        };
        t2.start();
    }
}
class Data{
    public synchronized void fun1(){
        //休眠3秒以后再进行输出
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("1....");
    }
    public synchronized void fun2(){
        System.out.println("2....");
    }

}

输出
在这里插入图片描述
其原因是t1线程首先启动后,将资源拿到,并锁住data对象,下一秒钟t2线程启动,但是func1和func2方法的调用者都是data对象,而且data对象目前被t1锁住,所以t2线程只能等待t1线程释放资源。而t1线程一旦释放资源,t2线程会马上获得资源,进行输出。所以t1和t2线程几乎同时输出。

3.验证synchronized是否锁的是data对象

①:我们将func2方法上的synchronized关键字去除
在这里插入图片描述
在这里插入图片描述
之所以会这样输出,是因为线程1虽然先启动,并锁住了data对象,但是t2线程执行的func2方法没有synchronized修饰,那么他也就不用去争抢data对象。所以直接输出。
②:不同的对象调用方法
在这里插入图片描述
在这里插入图片描述
用不同的data对象分别去调用被synchronized修饰的func1和func2方法,然后进行执行。
在这里插入图片描述
由于t1线程锁住的是data1对象,而t2线程需要的是data2对象,所以t2线程会直接执行

静态方法,锁定的是类

1:我们让fun1()和fun2()都变成静态方法。分别让data1对象和data2对象调用!!

在这里插入图片描述
在这里插入图片描述
输出结果:
在这里插入图片描述
t1线程和t2线程同时输出,这是因为当t1线程启动起来以后,他就会锁住Data类。等t2线程启动起来以后,t2线程无法获取Data类只能等代t1线程释放资源。等到t1线程释放资源,t2线程直接获取资源启动并输出。

2.验证我们锁定的是类

我们删除fun2()当中的synchronized关键字
在这里插入图片描述
输出结果
在这里插入图片描述
在这里插入图片描述
此时我们根据输出顺序得出一个结论,两个线程没有争抢资源,因为synchronized锁住的是类,而fun2并不是类方法,所以t2线程不需要争抢资源。

二、修饰代码块 锁定的是传入的对象

1.首先我们一次性创建五个线程,并调用同一资源

在这里插入图片描述
输出的结果是:5个线程同时执行,在等待1s后同时结束,因为此时没有资源的争抢。
在这里插入图片描述

2:使用代码块锁定的传入的对象

在这里插入图片描述
在这里插入图片描述
传入this关键字,锁住的是当前对象,也就是Data对象,那么输出的顺序一定是一个个的输出。
在这里插入图片描述
多个线程争抢同一资源,那么谁先抢到谁就可以将Data对象锁住,执行function方法

3.多个线程争抢同一资源,那么谁先抢到谁就可以将Data对象锁住,执行function方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4:换个东西锁一下,证明我们锁的是传入的对象!

在这里插入图片描述
在这里插入图片描述
要想访问function方法,就必须先要获取到 1 这个对象
在这里插入图片描述
至此我们可以得出结论:修饰代码块锁定的是传入的对象。

5.有趣的知识

在这里插入图片描述
在这里插入图片描述
我们发现这里的输出和上边的输出不一致,那么这是为什么呢?
128陷阱
在这里插入图片描述
在这里插入图片描述
解析:
答案就在Integet的valueOf()方当中,如果我们的数值在-128-127之间的数值都存储在有一个catch数组当中,该数组相当于一个缓存,当我们在-128-127之间进行自动装箱的时候,我们就直接返回该值在内存当中的地址,所以在-128-127之间的数值用==进行比较是相等的。而不在这个区间的数,需要新开辟一个内存空间,所以不相等。

相关推荐

  1. Synchronized升级过程

    2024-04-06 04:38:03       49 阅读
  2. 多线程(策略, synchronized 对应策略)

    2024-04-06 04:38:03       44 阅读
  3. synchronized底层加和释放原理

    2024-04-06 04:38:03       34 阅读
  4. synchronized 和 ReentrantLock 区别什么

    2024-04-06 04:38:03       44 阅读
  5. synchronized 和 Lock 区别什么

    2024-04-06 04:38:03       46 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-06 04:38:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-06 04:38:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-06 04:38:03       87 阅读
  4. Python语言-面向对象

    2024-04-06 04:38:03       96 阅读

热门阅读

  1. “头痛医头、脚痛医脚”的SAP解决方案

    2024-04-06 04:38:03       38 阅读
  2. 迁移Docker镜像存放目录

    2024-04-06 04:38:03       37 阅读
  3. Linux初学(十五)ssh服务

    2024-04-06 04:38:03       39 阅读
  4. matlab 坐标系变换

    2024-04-06 04:38:03       43 阅读
  5. MQ的作用及分类

    2024-04-06 04:38:03       43 阅读
  6. 11 - Debian如何限制sudo权限

    2024-04-06 04:38:03       36 阅读
  7. Docker-compose部署 gitlab-server

    2024-04-06 04:38:03       40 阅读
  8. 【数据结构】利用顺序表实现通讯录

    2024-04-06 04:38:03       40 阅读