zoukankan      html  css  js  c++  java
  • 深入理解Java并发synchronized同步化的代码块不是this对象时的操作

    本文仅仅是为了说明synchronized关键字同步的是对象不是方法,列子的确有失偏颇。

    一.明确一点synchronized同步的是对象不是方法也不是代码块 

     我有关synchronized同步的是对象讨论的博客在这里:https://www.cnblogs.com/SAM-CJM/p/9798263.html

     只要明确了synchronized同步的是对象那么,底下的问题就好解决了。

    二.问题的导入

     首先我有一个班级,班级中有学生。那么我们可以这样来模拟这个问题,代码如下:

    import java.util.ArrayList;
    
    public class Class {
        //班级类
        ArrayList<Student> students;
        public Class(ArrayList<Student> students){
            this.students=students;
        }
    
    }
    
    //学生类
    class Student{
        private String name;
        private int ID;
    
        public Student(String name,int ID){
            this.ID=ID;
            this.name=name;
        }
    }

     然后我们有一个班级事务处理类,来处理事务,这个类继承了Thread类代码入下:

    import java.util.ArrayList;
    import java.util.Arrays;
    
    public class ClassText extends Thread{//班级事务处理类
    
        Class class1;//待处理事务的班级
    
        //构造器
        public ClassText(Class class1){
            this.class1=class1;
        }
    
        @Override//没有同步run方法
        public void run(){
            super.run();
            addStudent(new Student("张三",15));
        }
    
        //添加学生,没有同步该方法
        public void addStudent(Student student){
                System.out.println("添加前现在有"+class1.students.size()+"个学生");
                class1.students.add(student);
                System.out.println("添加后现在有"+class1.students.size()+"个学生");
        }
    
        public static void main(String[] args) {
            Class c=new Class(new ArrayList<>(Arrays.asList(new Student("李四",20),new Student("赵牛",20))));
            ClassText ct1=new ClassText(c);
            ClassText ct2=new ClassText(c);
            ct1.start();
            ct2.start();
        }
    
    }

     显然上面的代码是错误的,他没同步两个线程,那么我们看看结果是什么样子的:

     果然出现了线程不安全的情况。

    那么,我们马上同步化我们的addStudent方法或者是run方法,代码如下:

    这里同步addStudent方法

        //添加学生,同步化该方法
        public synchronized void addStudent(Student student){
                System.out.println("添加前现在有"+class1.students.size()+"个学生");
                class1.students.add(student);
                System.out.println("添加后现在有"+class1.students.size()+"个学生");
        } 

    结果如下:

     还是不同步的。

    那么这到底是为什么呢?

    三.解决方法

    其实我们无论在ClassText类里面的哪个方法加synchronized使其同步化都是没有用的,因为你同步化的是你的ClassText对象,而我们要同步的是处理的是在ClassText类中组合Class对象,因为我们是对他的进行共享资源的操作,那么问题来了,怎么对不是本身对象进行一个同步化操作呢?还是使用synchronized同步代码块只不过同步对象不再是this了而是共享数据处理的对象,修改代码如下:

        //添加学生
        public  void addStudent(Student student){
            //同步化修改共享数据的对象
            synchronized (class1){
                System.out.println("添加前现在有"+class1.students.size()+"个学生");
                class1.students.add(student);
                System.out.println("添加后现在有"+class1.students.size()+"个学生");
            }
        }

    结果如下:没毛病了!

    当然你把添加学生的添加函数放到Class类中,同步改方法也是没问题的

    所以还是那一条,同步化的对象,是需要同步化的对象。

  • 相关阅读:
    1048. Find Coins (25)
    return view 详解 MVC
    EF Power Tool 代码生成器 反向生成
    对新数据库使用 Code First
    一个成熟的网站的架构设计应该是这样的
    公司业务的设计思想感悟
    请给奋斗中的男人们一次机会
    大话西游感悟
    充满恶意的单词
    lisp的解释器
  • 原文地址:https://www.cnblogs.com/SAM-CJM/p/9810385.html
Copyright © 2011-2022 走看看