zoukankan      html  css  js  c++  java
  • 架构系列——你可能不知道的那些synchronized使用细节

    作者专注于Java、架构、Linux、小程序、爬虫、自动化等技术。 工作期间含泪整理出一些资料,微信搜索【程序员高手之路】,回复 【java】【黑客】【爬虫】【小程序】【面试】等关键字免费获取资料。技术交流、项目合作可私聊:shuhao-99999。

    目录

    前言

    1、synchronized锁的重入性

    2、不要使用字符串常量作为锁

    3、锁对象的改变问题


    前言

    synchronized可以为任意对象加锁,用法比较灵活,语法如下

    (1)修饰代码块,作用于调用的对象;

    (2)修饰方法,作用于调用的对象;

    (3)修饰静态方法,作用于所有对象;

    (4)修饰类,作用于所有对象。

    synchronized取得的锁都是对象锁,而不是把一段代码(或者方法)当成锁!

    使用synchronized时,应该注意以下细节问题:

    1、synchronized锁的重入性

    如下列代码所示,类似于ReentrantLock

    在method1中没有释放锁的情况下,可以继续调用synchronized修饰的method2

    public class SyncDubbo {
        public synchronized void method1(){
            System.out.println("method1...");
            method2();
        }
        public synchronized void method2(){
            System.out.println("method2...");
            method3();
        }
        public synchronized void method3(){
            System.out.println("method1...");
        }
        
        public static void main(String[] args) {
            final SyncDubbo sd = new SyncDubbo();
            Thread t1 = new Thread(new Runnable(){
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    sd.method1();
                }
                
            }, "t1");
            t1.start();
        }
    }

     如下列代码所示,在子类与父类之间相互调用也运用了synchronized的重用性

    public class FatherSon {
        static class Father {
            public int num = 10;
            public synchronized void method1(){
                try {
                    num --;
                    System.out.println("Father num = " + num);
                    Thread.sleep(100);
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }
        }
        
        static class Son extends Father {
            public synchronized void method2(){
                try {
                    while (num >0) {
                        num --;
                        System.out.println("Son num = " + num);
                        Thread.sleep(100);
                        this.method1();
                    }
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }
        }
        public static void main(String[] args) {
            Thread t1 = new Thread(new Runnable(){
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    Son son = new Son();
                    son.method2();
                }
            }, "t1");
            t1.start();
        }
    }

    2、不要使用字符串常量作为锁

    如下列代码所示,使用了字符串常量作为锁,那么t1和t2运行之后将会一直在t1中出现死循环,t2永远拿不到锁!

    解决:可以使用 new String("字符串常量") 作为锁

    public class StringLock {
        public void method(){
            synchronized("字符串常量"){
                try {
                    while (true){
                        System.out.println("当前线程:" + Thread.currentThread().getName() + "开始");
                        Thread.sleep(1000);
                        System.out.println("当前线程:" + Thread.currentThread().getName() + "结束");
                    }
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }
        }
        
        public static void main(String[] args) {
            final StringLock sl = new StringLock();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    sl.method();
                }
                
            }, "t1");
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    sl.method();
                }
                
            }, "t2");
            t1.start();
            t2.start();
        }
    }

    3、锁对象的改变问题

    如下列代码所示,使用synchronized锁住了一个对象,并且在代码里重新new了一个对象,导致锁对象改变。

    这样在t1还没有运行完代码的时候,t2就已经可以拿到锁了,显然会出现问题!

    解决:不要改变锁对象(但是改变对象的属性对代码不会有影响,比如锁是一个人,那么可以改变这个人的身高、年龄等)

    public class ChangeLock {
        Object obj = new Object();
        
        public void method(){
            synchronized(obj){
                try {
                    System.out.println("当前线程:" + Thread.currentThread().getName() + "开始");
                    //从这里改变锁对象
                    obj = new Object();
                    Thread.sleep(3000);
                    System.out.println("当前线程:" + Thread.currentThread().getName() + "结束");
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }
        }
        public static void main(String[] args) {
            final ChangeLock cl = new ChangeLock();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    cl.method();
                }
                
            }, "t1");
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    cl.method();
                }
                
            }, "t2");
            t1.start();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            t2.start();
        }
    }
  • 相关阅读:
    电容在电路中的作用
    C语言中的弱符号(weak)用法及实例
    一种高灵敏度自带DSP降噪算法的音频采集解决方案
    高灵敏度自带DSP降噪算法的audio codec解决方案
    git clone error: RPC failed; curl 18 transfer closed with outstanding read data remaining
    stm32f103中freertos的tasks基本使用案例及备忘
    移植freertos到stm32 f103 的基本流程和总结
    stm32_f103使用gcc编译的环境下printf打印函数的实现
    C语言中指针和取地址符&的关系
    STM32中ARM系列编译工具链的编译宏选择(__CC_ARM、__ICCARM__、__GNUC__、__TASKING__)
  • 原文地址:https://www.cnblogs.com/shuhao66666/p/12925393.html
Copyright © 2011-2022 走看看