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

synchronized锁字符串

示例一

在没有使用synchronized锁的情况下:

import java.util.HashMap;
import java.util.Map;

public class NonSynchronizedSchoolExample {
    private static final Map<String, Integer> schoolCountMap = new HashMap<>();  // 存储每个学校的交卷数量

    public static void main(String[] args) {
        // 创建三个线程,模拟不同学校的学生交卷
        Thread thread1 = new Thread(new SubmitPaperTask("西华师范大学"), "Thread-1");
        Thread thread2 = new Thread(new SubmitPaperTask("西南石油大学"), "Thread-2");
        Thread thread3 = new Thread(new SubmitPaperTask("西南石油大学"), "Thread-3");

        thread1.start();
        thread2.start();
        thread3.start();
    }

    // 创建任务类,模拟学生交卷
    static class SubmitPaperTask implements Runnable {
        private final String school;

        public SubmitPaperTask(String school) {
            this.school = universityName;
        }

        @Override
        public void run() {
            // 直接访问并修改 HashMap,未考虑线程安全
            Integer count = schoolCountMap.get(school);
            if (count == null) {
                count = 0;  // 如果没有该学校的记录,默认值为0
            }
            // 模拟学生交卷
            System.out.println(school + " 的学生正在交卷...");
            try {
                Thread.sleep(1000);  // 模拟交卷时间
                schoolCountMap.put(school, count + 1);  // 增加该学校的交卷数量
                System.out.println(school + " 的学生交卷完毕! 当前交卷数量: " + (count + 1));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在没有使用synchronized的情况下,结果可能出现:

西华师范大学 的学生正在交卷...
西南石油大学 的学生正在交卷...
西华师范大学 的学生交卷完毕! 当前交卷数量: 1
西南石油大学 的学生交卷完毕! 当前交卷数量: 1
西南石油大学 的学生正在交卷...
西南石油大学 的学生交卷完毕! 当前交卷数量: 1

示例二

使用synchronized锁的情况下:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@RestController
public class SynchronizedSchoolController {

     // 存储每个学校的交卷数量
    private static final Map<String, Object> lockMap = new HashMap<>();  // 存储每个学校的锁对象

    // 接收交卷请求
    @GetMapping("/submitPaper/{school}")
    public String submitPaper(@PathVariable String school) {
        

        synchronized (this) {  // 锁住该学校的锁对象
            // 获取当前学校的交卷数量,如果没有则初始化为0
            Integer count = schoolCountMap.get(school);
            if (count == null) {
                count = 0;  // 如果没有该学校的记录,默认值为0
            }

            // 模拟学生交卷
            try {
                Thread.sleep(1000);  // 模拟交卷时间
                schoolCountMap.put(school, count + 1);  // 增加该学校的交卷数量
                return school + " 的学生交卷完毕! 当前交卷数量: " + (count + 1);
            } catch (InterruptedException e) {
                e.printStackTrace();
                return "交卷失败!";
            }
        }
    }
}

在这种情况下,synchronized锁住的当前实例对象,在这种情况下,我们都每一个线程都是串行执行的。

示例三:

我现在想要改进代码,我可以用synchronized锁住(school)这个字符串,这样不同学校的线程就是并行的,相同学校的就是串行执行的

。。。
synchronized (school)
。。。

使用synchronized锁school字符串的情况下,如果我们使用http接口的发送去请求的话,spring的底层不是发送传递的“西华师范大学”“西南石油大学”这样的字符串常量,而是通过new String(“西华师范大学”)这样的方式去传递string对象。这种情况下锁的资源是三个不同的对象,没有同一个资源的互斥,就会发送并行。

这涉及到 字符串池(String Pool)和 字符串对象的创建方式:

字符串常量(字符串池)

在 Java 中,字符串常量(例如 "西华师范大学")会被存储在一个特殊的内存区域,称为 字符串池。当你创建一个字符串常量时,JVM 会检查池中是否已经存在相同的字符串对象,如果存在,就会返回池中的引用,否则将该字符串放入池中。

String str1 = "西华师范大学";  // 会被存储在字符串池中
String str2 = "西华师范大学";  // str1 和 str2 引用同一个对象

通过 new String() 创建字符串对象

通过 new String("西华师范大学") 创建的字符串对象不再从字符串池中获取对象,而是直接在堆内存中创建一个新的 String 对象。这意味着,每次调用 new String() 都会创建一个新的对象,即使其内容与字符串池中的常量相同。

String str1 = new String("西华师范大学");  // 会在堆中创建一个新的 String 对象
String str2 = new String("西华师范大学");  // str1 和 str2 引用不同的对象

所以直接synchronized (school)还是会出现异常。

 

示例四:

为了解决示例三的问题,我们想到了直接synchronized ()字符串常量。 因为字符串常量都是存放在字符串常量池当中的,是唯一的,能够形成资源互斥。

synchronized(school.intern())

但是字符串常量池里面的字符串是全局唯一的,可能会阻塞相同锁资源的不同操作,所以进一步改进:

我们通过ConcurrentMap创建一个锁对象

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@RestController
public class SynchronizedSchoolController {

    // 使用 ConcurrentHashMap,确保线程安全
    private static final ConcurrentMap<String, Integer> schoolCountMap = new ConcurrentHashMap<>();  // 存储每个学校的交卷数量
    private static final ConcurrentMap<String, Object> lockMap = new ConcurrentHashMap<>();  // 存储每个学校的锁对象

    // 接收交卷请求
    @GetMapping("/submitPaper/{school}")
    public String submitPaper(@PathVariable String school) {
        // 获取每个学校的锁对象,确保每个学校有独立的锁
        Object lock = lockMap.computeIfAbsent(school, key -> new Object());

        synchronized (lock) {  // 锁住该学校的锁对象
            // 获取当前学校的交卷数量,如果没有则初始化为0
            Integer count = schoolCountMap.get(school);
            if (count == null) {
                count = 0;  // 如果没有该学校的记录,默认值为0
            }

            // 模拟学生交卷
            try {
                Thread.sleep(1000);  // 模拟交卷时间
                schoolCountMap.put(school, count + 1);  // 增加该学校的交卷数量
                return school + " 的学生交卷完毕! 当前交卷数量: " + (count + 1);
            } catch (InterruptedException e) {
                e.printStackTrace();
                return "交卷失败!";
            }
        }
    }
}


http://www.kler.cn/a/556169.html

相关文章:

  • 店铺矩阵崩塌前夜:跨境多账号运营的3个生死线
  • Prompt Engineering的重要性
  • 网络协议如何确保数据的安全传输
  • 达梦clob字段查询优化
  • Java Web开发实战与项目——Spring Boot与Redis实现缓存管理
  • 直播美颜工具架构设计与性能优化实战:美颜SDK集成与实时处理
  • 如何在Vue中更优雅地处理403错误?
  • 面试基础--微服务架构:如何拆分微服务、数据一致性、服务调用
  • 2025年2月一区SCI-海市蜃楼搜索优化算法Mirage search optimization-附Matlab免费代码
  • 初等数论--乘法逆元
  • 如何教计算机识别视频中的人类动作
  • 计算机网络之TCP的可靠传输
  • 【VSCode】MicroPython环境配置
  • 安全问答—评估和应用安全治理原则相关
  • 从CNN到Transformer:遥感影像目标检测的技术演进(矿产勘探、精准农业、城市规划、林业测量、军事目标识别和灾害评估等)
  • 23.3 HtmlElement类
  • 二叉树的前序、中序、后序遍历(递归和非递归实现)
  • MySQL 中的回表是什么?MySQL 中使用索引一定有效吗?如何排查索引效果?在 MySQL 中建索引时需要注意哪些事项?
  • Docker 的安全配置与优化(一)
  • STM32使用NRF2401进行数据传送