深入理解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类中,同步改方法也是没问题的
所以还是那一条,同步化的对象,是需要同步化的对象。
深入理解Java并发synchronized同步化的代码块不是this对象时的操作的更多相关文章
- Java的synchronized的同步代码块和同步方法的区别
synchronized同步方法和同步代码块的区别 同步方法默认使用this或者当前类做为锁. 同步代码块可以选择以什么来加锁,比同步方法更精确,我们可以选择只有会在同步发生同步问题的代码加锁,而并不 ...
- Java并发——synchronized关键字
前言: 只要涉及到Java并发那么我们就会考虑线程安全,实际上能够实现线程安全的方法很多,今天先介绍一下synchronized关键字,主要从使用,原理介绍 一.synchronized的使用方法 1 ...
- 精通java并发-synchronized关键字和锁
目前CSDN,博客园,简书同步发表中,更多精彩欢迎访问我的gitee pages synchronized关键字和锁 示例代码 public class MyThreadTest2 { public ...
- Java并发-Synchronized关键字
一.多线程下的i++操作的并发问题 package passtra; public class SynchronizedDemo implements Runnable{ private static ...
- 深入理解Java并发框架AQS系列(一):线程
深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 一.概述 1.1.前言 重剑无锋,大巧不工 读j.u.c包下的源码,永远无法绕开的经典 ...
- 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念
深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 一.AQS框架简介 AQS诞生于Jdk1.5,在当时低效且功能单一的synchroni ...
- 深入理解Java并发框架AQS系列(四):共享锁(Shared Lock)
深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 深入理解Java并发框架AQS系列(三):独占锁(Exclusive Lock) 深入 ...
- java 并发——synchronized
java 并发--synchronized 介绍 在平常我们开发的过程中可能会遇到线程安全性的问题,为了保证线程之间操作数据的正确性,我们第一想到的可能就是使用 synchronized 并且 syn ...
- java 为什么wait(),notify(),notifyAll()必须在同步(Synchronized)方法/代码块中调用?
wait()作用:该方法用来将当前线程置入休眠状态,直到接到通知或被中断为止.条件:在调用wait()之前,线程必须要获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait()方法.进入wai ...
随机推荐
- ps | grep排除grep这个进程
我们经常用ps | grep xxx来查询是否存在某进程,但默认情况下会将grep这个命令也作为结果返回,这样无论是否存在查询的进程,该命令的返回值都是0. 要避免这种情况可以使用grep的-v参数, ...
- 【题解】JSOIWC2019 Round 5
题面: 题解: T1: 算法1: 枚举每个灯塔的方向,并分别判断是否有解.时间复杂度O(K*4^K). 预计得分:50-70分 算法2: 不难发现,当k≥4的时候一定有解,将最靠左的两个下面的朝右上. ...
- Bugku-CTF之看看源代码吧
Day13 看看源代码吧 http://123.206.87.240:8002/web4/ 本题要点:url解码 首先看到文本框,我们还是要习惯性输入一下
- 利用JS打印质数
我爱撸码,撸码使我感到快乐!大家好,我是Counter,今天非常愉快,没有前几天的相对比较复杂的逻辑思维在里面,今天来写写,利用JS打印质数,基本上很多面试,会很经常的考到.那废话不多说,直接上代码: ...
- IVIEW对的table组件超出长度用省略号代替,使用气泡提示。
render: (h, params) => { return h('div', [ h('Tooltip', { props: { placement: 'top' } }, [ h('spa ...
- 再谈git和github-深入理解-3
git tag -a 和 -m的区别? -a是 注解 是单词 "annotate"的意思 , 表示 "给标签一个名字, 标签名 -m 是创建标签时的消息备注 git ta ...
- HDU 5405 Sometimes Naive(动态树)
题意 \(n\) 个节点的树,每个点有点权,\(m\) 次操作,操作分两种,修改一个节点的点权,对于一个 \((u,v)\) ,询问 \(\displaystyle\sum_{i=1}^n\sum_{ ...
- 【Git】Git使用记录: 撤回已经commit到本地的提交记录
话不多说直接上步骤: git bash直接干到你的code. 直接敲命令: git reset --soft HEAD~1 搞定 就是这么简单粗暴. 如有顾虑请自行找个案例测试即可. 参考资料 htt ...
- ASP.NET图片上传(配合jquery.from.js 插件)
前端: js: function AjaxKouBeiShopEdit() { var options = { dataType: "json&q ...
- ES5 map循环一大坑:循环遍历竟然出现逗号!
一.map map大法好 这里需要解释一下Map和forEach的区别 一般来说需要返回值时使用Map,而只需要循环的使用forEach map循环常用的一些方法 /********* ES6 *** ...