Synchronized

简介: JUC学习

Synchronized 关键

synchronized 是 Java 中的关键字,是一种同步锁。它修饰的对象有以下几种:

1.修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}

括起来的代码,作用的对象是调用这个代码块的对象;

2.修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;

虽然可以使用 synchronized 来定义方法,但synchronized 并不属于方法定义

的一部分,因此,synchronized 关键字不能被继承。如果在父类中的某个方法

使用了 synchronized 关键字,而在子类中覆盖了这个方法,在子类中的这个方

法默认情况下并不是同步的,而必须显式地在子类的这个方法中加上synchronized 关键字才可以。当然,还可以在子类方法中调用父类中相应的方

法,这样虽然子类中的方法不是同步的,但子类调用了父类的同步方法,因此,子类的方法也就相当于同步了。

3.修饰一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;

4.修饰一个类,其作用的范围是 synchronized 后面括号括起来的部分,作用主

的对象是这个类的所有对象。


对象锁:包括方法锁(默认锁对象为this,当前实例对象)和同步代码块锁(自己指定锁对象)

著作权归https://pdai.tech所有。
链接:https://pdai.tech/md/java/thread/java-thread-x-key-synchronized.html
public class SynchronizedObjectLock implements Runnable {
    static SynchronizedObjectLock instence = new SynchronizedObjectLock();
    @Override
    public void run() {
        // 同步代码块形式——锁为this,两个线程使用的锁是一样的,线程1必须要等到线程0释放了该锁后,才能执行
        synchronized (this) {
            System.out.println("我是线程"+ Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() +"结束");
        }
    }
    public static void main(String[] args) {
        Thread t1 = new Thread(instence);
        Thread t2 = new Thread(instence);
        t1.start();
        t2.start();
    }
}

输出结果:

我是线程Thread-0
Thread-0结束
我是线程Thread-1
Thread-1结束
public class SynchronizedObjectLock implements Runnable {
    static SynchronizedObjectLock instence = new SynchronizedObjectLock();
    // 创建2把锁
    Object block1 = new Object();
    Object block2 = new Object();
    @Override
    public void run() {
        // 这个代码块使用的是第一把锁,当他释放后,后面的代码块由于使用的是第二把锁,因此可以马上执行
        synchronized (block1) {
            System.out.println("block1锁,我是线程"+ Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("block1锁,"+Thread.currentThread().getName() +"结束");
        }
        synchronized (block2) {
            System.out.println("block2锁,我是线程"+ Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("block2锁,"+Thread.currentThread().getName() +"结束");
        }
    }
    public static void main(String[] args) {
        Thread t1 = new Thread(instence);
        Thread t2 = new Thread(instence);
        t1.start();
        t2.start();
    }
}

结果:

block1锁,我是线程Thread-0
block1锁,Thread-0结束
block2锁,我是线程Thread-0  // 可以看到当第一个线程在执行完第一段同步代码块之后,第二个同步代码块可以马上得到执行,因为他们使用的锁不是同一把
block1锁,我是线程Thread-1
block2锁,Thread-0结束
block1锁,Thread-1结束
block2锁,我是线程Thread-1
block2锁,Thread-1结束

方法锁形式:synchronized修饰普通方法,锁对象默认为this

著作权归https://pdai.tech所有。
链接:https://pdai.tech/md/java/thread/java-thread-x-key-synchronized.html
public class SynchronizedObjectLock implements Runnable {
    static SynchronizedObjectLock instence = new SynchronizedObjectLock();
    @Override
    public void run() {
        method();
    }
    public synchronized void method() {
        System.out.println("我是线程"+ Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() +"结束");
    }
    public static void main(String[] args) {
        Thread t1 = new Thread(instence);
        Thread t2 = new Thread(instence);
        t1.start();
        t2.start();
    }
}

输出结果:

我是线程Thread-0
Thread-0结束
我是线程Thread-1
Thread-1结束

类锁:指synchronize修饰静态的方法或指定锁对象为Class对象

synchronize修饰静态方法

public class SynchronizedObjectLock implements Runnable {
    static SynchronizedObjectLock instence1 = new SynchronizedObjectLock();
    static SynchronizedObjectLock instence2 = new SynchronizedObjectLock();
    @Override
    public void run() {
        method();
    }
    // synchronized用在普通方法上,默认的锁就是this,当前实例
    public synchronized void method() {
        System.out.println("我是线程"+ Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() +"结束");
    }
    public static void main(String[] args) {
        // t1和t2对应的this是两个不同的实例,所以代码不会串行
        Thread t1 = new Thread(instence1);
        Thread t2 = new Thread(instence2);
        t1.start();
        t2.start();
    }
}

输出结果

我是线程Thread-0
我是线程Thread-1
Thread-1结束
Thread-0结束

实例2:

public class SynchronizedObjectLock implements Runnable {
    static SynchronizedObjectLock instence1 = new SynchronizedObjectLock();
    static SynchronizedObjectLock instence2 = new SynchronizedObjectLock();
    @Override
    public void run() {
        method();
    }
    // synchronized用在静态方法上,默认的锁就是当前所在的Class类,所以无论是哪个线程访问它,需要的锁都只有一把
    public static synchronized void method() {
        System.out.println("我是线程"+ Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() +"结束");
    }
    public static void main(String[] args) {
        Thread t1 = new Thread(instence1);
        Thread t2 = new Thread(instence2);
        t1.start();
        t2.start();
    }
}

输出结果:

我是线程Thread-0
Thread-0结束
我是线程Thread-1
Thread-1结束

synchronized指定锁对象为Class对象

public class SynchronizedObjectLock implements Runnable {
    static SynchronizedObjectLock instence1 = new SynchronizedObjectLock();
    static SynchronizedObjectLock instence2 = new SynchronizedObjectLock();
    @Override
    public void run() {
        // 所有线程需要的锁都是同一把
        synchronized(SynchronizedObjectLock.class){
            System.out.println("我是线程"+ Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() +"结束");
        }
    }
    public static void main(String[] args) {
        Thread t1 = new Thread(instence1);
        Thread t2 = new Thread(instence2);
        t1.start();
        t2.start();
    }
}

输出结果:

我是线程Thread-0
Thread-0结束
我是线程Thread-1
Thread-1结束


目录
相关文章
|
Java Apache Maven
使用checkstyle来规范你的项目
Checkstyle是什么 自从做了程序员,关于格式化的讨论就不曾中断过,到底什么才是正确的,什么才是错误的,到现在也没有完整的定论。但随着时间发展,渐渐衍生出一套规范出来。没有什么绝对的正确和错误,关键在于规范的定义。
6102 0
|
数据采集 存储 数据挖掘
BDCC - 闲聊数据仓库的架构
BDCC - 闲聊数据仓库的架构
535 0
|
5月前
|
存储 自然语言处理 前端开发
抖音快手小红书虚拟评论截图生成器,模拟对话制作工具,html+js+css
这是一款纯前端实现的多平台虚拟评论生成器,支持抖音、快手、小红书风格,适用于产品演示与UI设计。采用Vanilla JS与Flexbox布局,利用IndexedDB存储数据,CSS Variables切换主题。
|
6月前
|
人工智能 算法 NoSQL
LRU算法的Java实现
LRU(Least Recently Used)算法用于淘汰最近最少使用的数据,常应用于内存管理策略中。在Redis中,通过`maxmemory-policy`配置实现不同淘汰策略,如`allkeys-lru`和`volatile-lru`等,采用采样方式近似LRU以优化性能。Java中可通过`LinkedHashMap`轻松实现LRUCache,利用其`accessOrder`特性和`removeEldestEntry`方法完成缓存淘汰逻辑,代码简洁高效。
293 0
|
11月前
|
存储 C语言 开发者
【C语言】格式化输出占位符及其标志字符详解(基于ISO/IEC 9899:2024)
在C语言中,格式化输出通过 `printf` 函数等格式化输出函数来实现。格式说明符(占位符)定义了数据的输出方式,标准ISO/IEC 9899:2024(C23)对这些格式说明符进行了详细规定。本文将详细讲解格式说明符的组成部分,包括标志字符、宽度、精度、长度修饰符和类型字符,并适当增加表格说明。
801 6
|
监控 网络协议 网络安全
识别DDoS攻击
【10月更文挑战第12天】识别DDoS攻击
450 16
|
人工智能
[AI Google] TimesFM:AI预测股市价格,能否助我财务自由?
探索谷歌TimesFM模型,看看它能否通过预测股票价格帮助我们实现财务自由。
[AI Google] TimesFM:AI预测股市价格,能否助我财务自由?
|
存储 弹性计算 人工智能
【阿里云弹性计算】深度解析阿里云ECS弹性裸金属服务器:性能与弹性的完美平衡
【5月更文挑战第24天】阿里云ECS弹性裸金属服务器融合物理机高性能与云服务弹性,提供计算、存储及网络优势。支持秒级伸缩、自动扩展,适用于高性能计算、游戏、企业应用及AI场景。示例代码展示如何通过CLI创建实例,是高需求场景的理想选择。
618 0
idea报错URI is not registered (Settings | Languages & Frameworks | Schemas and DTDs)
idea报错URI is not registered (Settings | Languages & Frameworks | Schemas and DTDs)
idea报错URI is not registered (Settings | Languages & Frameworks | Schemas and DTDs)
|
缓存 前端开发 搜索推荐
【Flutter前端技术开发专栏】Flutter中的自定义绘制与Canvas API
【4月更文挑战第30天】Flutter允许开发者通过`CustomPaint`和`CustomPainter`进行自定义绘制,以实现丰富视觉效果。`CustomPaint` widget将`CustomPainter`应用到画布,而`CustomPainter`需实现`paint`和`shouldRepaint`方法。`paint`用于绘制图形,如示例中创建的`MyCirclePainter`绘制蓝色圆圈。Canvas API提供绘制形状、路径、文本和图片等功能。注意性能优化,避免不必要的重绘和利用缓存提升效率。自定义绘制让Flutter UI更具灵活性和个性化,但也需要图形学知识和性能意识。
262 0
【Flutter前端技术开发专栏】Flutter中的自定义绘制与Canvas API

热门文章

最新文章