java 多线程: Thread 并发访问-代码块同步synchronized {};String作为被锁的对象

方法同步的弊端

方法同步的时候,如果一个方法需要线程安全控制的代码速度其实很快,但是有其他的业务逻辑代码耗时非常长(比如网络请求),这样所有的线程就在这一块就等待着了,这样造成了极大的资源浪费如果并发量很大,可能会造成系统崩溃。(并发的线程遇到synchronized同步的方法,变成串行....

并发访问-代码块同步

语法:

synchronized (要锁住的对象) {
  并发执行且不耗时的业务计算代码;
}
 
代码示例: 方法同步比代码块同步耗时天壤地别
复制代码
import java.util.HashSet;
import java.util.Set;

/**
 * @ClassName ThreadSyncCode
 * @projectName: object1
 * @author: Zhangmingda
 * @description: XXX
 * date: 2021/4/22.
 */
public class ThreadSyncCode {
    //子线程类外公共用来计算的变量
    private static int num = 0;
    //子线程对象
    private static class MyRannable implements Runnable {
        @Override
        public void run() {  //这里synchronized 导致耗时的IO操作也变为串行
            /**
             * 模拟网络IO,磁盘IO耗时等待操作
             */
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            /**
             * 避免多线程同时计算的代码块改为同步代码块。变为多线程到此串行执行;上面的IO耗时操作仍然并行
             */
            synchronized (getClass()){
                for (int i=0; i<1000; i++){
                    num++;
                }
            }
            System.out.println(Thread.currentThread().getName() + " num result:" + num);
        }
    }
    public static void main(String[] args) {
        Set<Thread> threads = new HashSet<>();
        MyRannable myRannable = new MyRannable();
        for (int i=0; i<5; i++){
            threads.add(new Thread(myRannable,"线程"+i));
        }
        threads.forEach(thread -> thread.start());

        try {
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("main num result:" + num);
    }

}
复制代码

方法同步IO耗时串行导致长达5S出结果。而代码块同步耗时1S多结束。

String作为被锁的对象

复制代码
import java.util.HashSet;
import java.util.Set;

/**
 * @ClassName ThreadMultiObjectSyncStringLock
 * @projectName: object1
 * @author: Zhangmingda
 * @description: XXX
 * date: 2021/4/22.
 */
public class ThreadMultiObjectSyncStringLock {
    private static int num = 0;
    private static class MyThread extends Thread{
        private String lock;

        public MyThread(String name, String lock) {
            super(name);
            this.lock = lock;
        }

        @Override
        public void run() {
            synchronized (lock){
                for (int i=0; i<1000; i++){
                    num++;
                }
                System.out.println(Thread.currentThread().getName() + "   num:" + num);
            }
        }
    }
    public static void main(String[] args) {
        //String锁对象
        String lock = "LOCK";
        //存放线程的集合
        Set<MyThread> myThreads = new HashSet<>();
        //向集合添加线程实例
        for (int i=0; i<5; i++){
            myThreads.add(new MyThread("T" +i, lock));
        }
        //启动所有线程
        myThreads.forEach(myThread -> myThread.start());
        //稍等时间主线程查看结果
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "num Result:" + num); //5000完全正确
    }
}
复制代码
结果:最终打印出来的num的值就是5000,结果是正确的。但是我们发现我们在for循环创建我们的线程的时候,我们定义了5次lock,但是实际上这些lock是同一个对象(指向的是同一个内存地址),因为在JAVA中,字符串具有常量缓存的功能。所以会被锁起来。

 

posted on   zhangmingda  阅读(193)  评论(0编辑  收藏  举报

编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2020-04-22 深入理解css中position属性及z-index属性 https://www.cnblogs.com/zhuzhenwei918/p/6112034.html
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示