深刻理解Java并发synchronized同步化的代码块不是this对象时的操做

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

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

 我有关synchronized同步的是对象讨论的博客在这里:http://www.javashuo.com/article/p-hqlnozga-x.html安全

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

二.问题的导入函数

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

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类代码入下:spa

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();
    }

}

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

 果真出现了线程不安全的状况。code

那么,咱们立刻同步化咱们的addStudent方法或者是run方法,代码以下:htm

这里同步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类中,同步改方法也是没问题的

因此仍是那一条,同步化的对象,是须要同步化的对象。

相关文章
相关标签/搜索