深入理解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類中,同步改方法也是沒問題的

所以還是那一條,同步化的對象,是需要同步化的對象。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM