本文仅仅是为了说明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类中,同步改方法也是没问题的

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

深入理解Java并发synchronized同步化的代码块不是this对象时的操作的更多相关文章

  1. Java的synchronized的同步代码块和同步方法的区别

    synchronized同步方法和同步代码块的区别 同步方法默认使用this或者当前类做为锁. 同步代码块可以选择以什么来加锁,比同步方法更精确,我们可以选择只有会在同步发生同步问题的代码加锁,而并不 ...

  2. Java并发——synchronized关键字

    前言: 只要涉及到Java并发那么我们就会考虑线程安全,实际上能够实现线程安全的方法很多,今天先介绍一下synchronized关键字,主要从使用,原理介绍 一.synchronized的使用方法 1 ...

  3. 精通java并发-synchronized关键字和锁

    目前CSDN,博客园,简书同步发表中,更多精彩欢迎访问我的gitee pages synchronized关键字和锁 示例代码 public class MyThreadTest2 { public ...

  4. Java并发-Synchronized关键字

    一.多线程下的i++操作的并发问题 package passtra; public class SynchronizedDemo implements Runnable{ private static ...

  5. 深入理解Java并发框架AQS系列(一):线程

    深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 一.概述 1.1.前言 重剑无锋,大巧不工 读j.u.c包下的源码,永远无法绕开的经典 ...

  6. 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念

    深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 一.AQS框架简介 AQS诞生于Jdk1.5,在当时低效且功能单一的synchroni ...

  7. 深入理解Java并发框架AQS系列(四):共享锁(Shared Lock)

    深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 深入理解Java并发框架AQS系列(三):独占锁(Exclusive Lock) 深入 ...

  8. java 并发——synchronized

    java 并发--synchronized 介绍 在平常我们开发的过程中可能会遇到线程安全性的问题,为了保证线程之间操作数据的正确性,我们第一想到的可能就是使用 synchronized 并且 syn ...

  9. java 为什么wait(),notify(),notifyAll()必须在同步(Synchronized)方法/代码块中调用?

    wait()作用:该方法用来将当前线程置入休眠状态,直到接到通知或被中断为止.条件:在调用wait()之前,线程必须要获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait()方法.进入wai ...

随机推荐

  1. IDEA设置(含永久破解IDEA)

    永久破解IDEA(很多license服务器都是非永久性的,太麻烦了) https://www.cnblogs.com/iathanasy/p/9469280.html,亲测. 在我们为 IDEA 等编 ...

  2. [C++ Primer Plus] 第3章、处理数据(二)课后习题

    1 . 编写一个小程序,要求用户使用一个整数输出自己的身高(单位为厘米),然后将身高转换为米和厘米.该程序使用下划线字符来指示输入位置.另外,使用一个 const 符号常量来表示转换因子. #incl ...

  3. Python3 tkinter基础 Menu 添加菜单栏

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  4. UnicodeMath数学公式编码_翻译(Unicode Nearly Plain - Text Encoding of Mathematics Version 3)

    目录 完整目录 1. 简介 2. 编码简单数学表达式 2.1 分数 2.2 上标和下标 2.3 空白(空格)字符使用 3. 编码其他数学表达式 3.1 分隔符 强烈推荐本文简明版UnicodeMath ...

  5. redis编译问题

    在编译redis时,出现以下问题 In file included from adlist.c:34:0: zmalloc.h:50:31: fatal error: jemalloc/jemallo ...

  6. windows同时安装了两种jdk

    因为某种需要,同时安装jdk1.8 和jdk1.7 因为电脑曾经安装了jdk1.8,并且已经设置好环境变量.后来新添加的jdk1.7 出现问题: 先是安装的1.8,之后有安装了1.7,在环境变量中也配 ...

  7. 关于ios 11 的问题

    https://segmentfault.com/a/1190000011444121

  8. redis-server 使用

    redis.conf ################################## NETWORK ##################################### bind 127 ...

  9. MySQL5.5安装教程

                                          登录MySQL:mysql -uroot -p密码 退出MySQL:exit | quit 查看数据库:show datab ...

  10. SQL SERVER 游标循环读取表数据

    [cursor]游标:用于循环表行数据,类似指针 格式如下: declare tempIndex cursor for (select * from table) --定义游标 open tempIn ...