当前位置: 首页 > wzjs >正文

深圳高端网站设计公司最新的销售平台

深圳高端网站设计公司,最新的销售平台,上海知名网站建设公司,网站自动更新👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD 🔥 2025本人正在沉淀中… 博客更新速度 👍 欢迎点赞、收藏、关注,跟上我的更新节奏 📚欢迎订阅专栏…

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD
🔥 2025本人正在沉淀中… 博客更新速度++
👍 欢迎点赞、收藏、关注,跟上我的更新节奏
📚欢迎订阅专栏,专栏别名《在2B工作中寻求并发是否搞错了什么》

文章目录

  • 前言
  • 入门
    • 什么是synchronized?
    • 为什么用synchronized?
    • 怎么用synchronized?
      • 修饰方法
      • 修饰代码块
  • syncrhonized在框架源码中的使用
    • Vector 和 Hashtable
    • StringBuffer
  • 总结
    • synchronized的优点
    • synchronized的缺点
    • synchronized的适用场景
  • 后话
  • 参考

前言

这一篇同样是sychronzied的入门篇,不会涉及底层原理和实现,很适合初学者的学习。好了, 不废话了,让我们马上开始吧🤗

入门

什么是synchronized?

synchronized 是 Java 中的关键字,用于实现线程同步,确保多个线程在访问共享资源时不会发生冲突。它可以修饰方法或代码块,保证同一时间只有一个线程执行被修饰的代码,从而避免数据不一致问题。

为什么用synchronized?

  1. 解决竞态条件(Race Condition)

问题:多个线程同时修改同一个共享变量时,操作顺序可能被打乱,导致结果不可预测。
如果两个线程同时调用 increment(),可能发生以下情况:线程 A 读取 count=0 → 线程 B 也读取 count=0 → 两者都改为 1 → 最终 count=1(实际应为 2)。

// 有问题的count++
public class Counter {private int count = 0;public void increment() {count++; // 这行代码实际包含三步:读取值 → 修改值 → 写回值}
} 

解决:使用synchronized解决,synchronized确保同一时刻只有一个线程能执行increment(),避免值被覆盖。

public class Counter {private int count = 0;// 添加 synchronized 关键字public synchronized void increment() {count++; // 现在是一个原子操作}
}
  1. 保证内存可见性

问题:线程有自己的工作内存(缓存),修改共享变量后可能不会立即同步到主内存,导致其他线程看到旧值。

// 存在问题的flag读和写方法
public class VisibilityDemo {private boolean flag = false;public void setFlag() {flag = true; // 线程 A 修改 flag}public void checkFlag() {while (!flag); // 线程 B 可能永远看不到 flag 变为 true}
}

解决:使用synchronized解决,通过 synchronized 的锁机制,强制线程从主内存读取最新值,避免可见性问题。

public class VisibilityDemo {private boolean flag = false;// 添加 synchronized 保证可见性public synchronized void setFlag() {flag = true; // 修改后立即同步到主内存}// 同样用 synchronized 读取public synchronized boolean checkFlag() {return flag; // 从主内存读取最新值}
}
  1. 避免原子性破坏

问题:某些操作看似是“一步完成”,但实际由多个底层指令组成(如 i++),多线程环境下可能被分割执行,比如下面的转账例子。

// 非原子操作
public void transfer(Account from, Account to, int amount) {if (from.balance >= amount) {from.balance -= amount; // 非原子操作to.balance += amount;    // 可能被其他线程打断}
}

解决:使用synchronized解决。这里更安全的做法是使用全局锁(如定义一个 final Object lock),避免嵌套锁导致的死锁风险。

public void transfer(Account from, Account to, int amount) {// 锁定两个账户对象,避免并发修改synchronized (from) {synchronized (to) {if (from.balance >= amount) {from.balance -= amount;to.balance += amount;}}}
}
  1. 协调多线程的有序访问

问题:多个线程需要按特定顺序操作共享资源(如生产者-消费者模型)。

public class Queue {private List<Integer> list = new ArrayList<>();public synchronized void add(int value) {list.add(value); // 生产者线程添加数据}public synchronized int remove() {return list.remove(0); // 消费者线程移除数据}
}

解决synchronized 确保同一时刻只有一个线程操作队列,避免并发异常。

public class Queue {private List<Integer> list = new ArrayList<>();// 添加和移除方法均用 synchronized 保护public synchronized void add(int value) {list.add(value);}public synchronized int remove() {if (!list.isEmpty()) {return list.remove(0);}return -1; // 或抛异常}
}

怎么用synchronized?

我们可以看到,JLS已经规定了,可以修饰在方法和代码块中。
在这里插入图片描述

修饰方法

1.修饰实例方法
锁是当前对象实例(this),同一对象的多个线程调用该方法时会互斥。

public class Counter {private int count = 0;// 修饰实例方法:锁是当前对象实例public synchronized void increment() {count++;}
}

使用场景:多个线程操作同一个对象的实例方法时(如单例对象的资源修改)。

2.修饰静态方法
锁是类的 Class 对象(如 Counter.class),所有线程调用该类的静态方法时会互斥。

public class Counter {private static int count = 0;// 修饰静态方法:锁是 Counter.classpublic static synchronized void increment() {count++;}
}

使用场景:多线程操作静态变量(如全局计数器)。

修饰代码块

可以指定任意对象作为锁,灵活性更高。

1.锁是当前对象实例(this)

public void doSomething() {// 同步代码块:锁是当前对象实例synchronized (this) {// 需要同步的代码}
}

2.锁是类对象(Class)

public void doSomething() {// 同步代码块:锁是 Counter.classsynchronized (Counter.class) {// 需要同步的代码}
}

3.锁是任意对象

private final Object lock = new Object();public void doSomething() {// 同步代码块:锁是自定义对象synchronized (lock) {// 需要同步的代码}
}

syncrhonized在框架源码中的使用

Vector 和 Hashtable

这些类在 JDK 早期版本中通过synchronized修饰所有公共方法实现线程安全。例如Vectoradd() 方法:

public synchronized boolean add(E e) {modCount++;ensureCapacityHelper(elementCount + 1);elementData[elementCount++] = e;return true;
}

缺点:锁粒度粗(整个方法加锁),性能较低,现代开发中多被ConcurrentHashMapCollections.synchronizedList()替代。

StringBuffer

StringBuffer的方法均用synchronized修饰以实现线程安全,例如append()

public synchronized StringBuffer append(String str) {toStringCache = null;super.append(str);return this;
}

总结

synchronized的优点

  1. 简单易用
    • 只需在方法或代码块上添加关键字即可实现线程同步,无需手动管理锁的获取和释放。
  2. 自动释放锁
    • 当同步代码块执行完毕或发生异常时,锁会自动释放,避免死锁风险。
  3. 内置锁优化
    • JVM 对 synchronized 进行了大量优化,如锁升级机制(偏向锁 → 轻量级锁 → 重量级锁),在低竞争场景下性能较好。
  4. 内存可见性
    • 通过 synchronized 的锁机制,可以保证线程对共享变量的修改对其他线程可见(遵循 happens-before 原则)。
  5. 结构化锁
    • 锁的获取和释放必须成对出现,减少编码错误。

synchronized的缺点

  1. 性能开销
    • 在高竞争场景下,synchronized 会升级为重量级锁,导致线程阻塞和上下文切换,性能较差。
  2. 锁粒度较粗
    • 如果直接修饰方法,可能导致锁的范围过大,降低并发性能。
  3. 不可中断
    • 线程在等待锁时无法被中断(Lock 接口支持可中断的锁获取)。
  4. 功能有限
    • 不支持尝试获取锁(tryLock)、超时获取锁、公平锁等高级功能(ReentrantLock 支持)。
  5. 嵌套锁可能导致死锁
    • 如果多个线程以不同顺序获取嵌套锁,可能导致死锁。

synchronized的适用场景

  1. 低竞争场景
    • 当线程竞争不激烈时,synchronized 的性能足够好,且实现简单。
  2. 简单的线程同步需求
    • 如计数器、单例模式、简单的生产者-消费者模型等。
  3. 需要快速实现线程安全
    • 在开发初期或对性能要求不高的场景下,synchronized 是快速实现线程安全的有效工具。
  4. 需要保证内存可见性
    • 当多个线程需要共享变量时,synchronized 可以确保变量的修改对其他线程可见。
  5. 锁粒度较粗的场景
    • 如果锁的范围不需要特别精细,直接修饰方法即可满足需求。

后话

什么就结束了?别急,这个synchronized的原理,也是很有说法的。

点上关注,主播马上带你们深入学习synchronized

最近主播的下班时间都是准点,这下沉淀爽了🤗

参考

Chapter 17. Threads and Locks

http://www.dtcms.com/wzjs/501019.html

相关文章:

  • 对外贸营销型网站建设的几点建议河南品牌网络推广外包
  • 为代理赌博做网站常州网站建设
  • 网站开发项目进度表长春百度推广电话
  • 简约创意logo图片大全南昌seo全网营销
  • 怎么做多语言网站全国广告投放平台
  • 南县做网站推荐博客seo怎么做
  • 网站建设合同书-详细版关于进一步优化
  • 网站开发通用流程图百度官方首页
  • 唐山做网站优化宁波靠谱营销型网站建设
  • 如何做图让网站的图更清晰网站规划与设计
  • 做网站建设的联系电话百度收录怎么做
  • 网站的构成国外推广网站
  • 江门h5模板建站网络营销课程实训报告
  • 百度网站的域名是什么今天新闻
  • 青岛网站建设推广百度app登录
  • 莆田seo谷歌seo服务公司
  • 3g下订单的网站怎么做专业营销策划团队
  • 北京十大网站建设公司如何自己创建一个网站
  • 做网站客户端发帖推广
  • 白银网站建设公司国家认可的教育培训机构
  • 网站建设公司专业网站开发制作网店运营是做什么的
  • 营销型网站建设的特别之处都有哪些今天最新新闻事件报道
  • 外贸展示网站多少钱免费查权重工具
  • 为什么要立刻做网站售卖链接
  • 传奇私服哪个网站做的好网站推广app
  • 网站开发的最初阶段包括站长工具seo排名查询
  • 阿里云备案 网站备案域名购买微信公众号怎么做文章推广
  • 自己怎么样做游戏网站国家培训网官网
  • 全国代运营最好的公司百度seo排名优化提高流量
  • wordpress title 竖线seo搜索引擎优化入门