Java并发编程笔记1-竞争条件&初识原子类&可重入锁
我们知道,在多线程访问一个共享变量的时候会发生安全问题。
首先看下面例子:
public class Counter {
private int count; public void add(){
try{
for (int i = 0;i<200;i++){
Thread.sleep(100);
this.count++;
System.out.println(this.count);
}
}catch (Exception e ){
e.printStackTrace();
}
}
}
public class Test {
public static void main(String[] args) {
final Counter counter = new Counter(); new Thread(new Runnable() {
public void run() {
counter.add();
}
}).start(); new Thread(new Runnable() {
public void run() {
counter.add();
}
}).start(); new Thread(new Runnable() {
public void run() {
counter.add();
}
}).start();
}
}
运行结果如下:
如果没发生线程对数据的赃操作,3个线程执行,结果会累加到600的,看上面结果明显没有,并且出现一下重复的数据。这是因为存在3个线程同时操作同一个数字,导致输出重复数字。
解决办法:
1.在方法上加上synchronized关键字。如下图:
虽然结果不会出现重复,但是synchronized效率及其低下,运行速度明显被拖慢。原因是,for循环中的i变量是每个线程都有独自的局部变量,各不影响,但是每个线程都要排队进入这个方法,排队睡觉,这样就导致效率低下
2.在竞争条件上加synchronized,我们知道各个线程其实竞争的是count这个成员变量。因此在此地方加即可。如下图:
这样运行效率比方法一快了很多,因为省去了排队进入方法,排队睡觉。只需要排队取count值即可,这样效率比方法一快。
注意上图中,输出语句并不是竞争条件,并不一定要放在synchroized里面,这里放在里面是为了让线程取到值自增后立即输出,这样输出就不会发生混论,不发生抢占输出问题,一样能累加到600,
如果把输出放在synchronized外面会出现值有重复现象,因为累加后的值并没有立即输出,这样导致输出混乱,但仍然能加到600.知识输出不安全罢了。
3.使用原子类型,比如将上面的代码的int count类型改成AtomicInteger count类型,我们知道获取count的值然后再自加个1是可能会出现问题的,也就是结果出现重复数字。AtomicInteger类型是以同步的方法解决这个问题的。如下图:
结果如下图:
可以看到数字的输出没有严格的排队,但是数据确实给你保证的了,就是完整的加到600.这也恰恰因为不是严格的进行排队,才是的这种方法比前面两种方法的效率大大改进。
理论总结:synchronized是一种内部锁,就是所对象内部给我们提供的,因为每一个对象有一个状态变量,相当于一个锁,进入同步块,改变这个变量。别的线程进入之后就要判断这个变量有没有改变。
一个线程获取它本生已经持有的锁,这是可以成功的。我们知道多个线程同时抢占同一个锁它们是失败的。因为它们之间是互斥的。但是呢,一个线程再次获取一个自己已经拿过的锁是可以成功的,那么它是能够成功的。
看如下例子:
public class Widget { public synchronized void doSth(){ } }
public class ChildWidget extends Widget {
@Override
public synchronized void doSth() {
super.doSth();
}
}
public class Test {
public static void main(String[] args) { Widget w = new ChildWidget();
w.doSth();
}
}
子类调用自己的方法的那个synchroized那个锁是w对象的这个锁,而在子类方法中的super.doSth()父类中的方法的synchronized的锁也是w对象的锁。因此不要被子类继承父类的方法中的锁所迷惑了。
因此这种方式叫做内部锁的可重入机制,也叫可重入锁。
Java并发编程笔记1-竞争条件&初识原子类&可重入锁的更多相关文章
- java并发编程(十四)----(JUC原子类)对象的属性修改类型介绍
今天我们介绍原子类的最后一个类型--对象的属性修改类型: AtomicIntegerFieldUpdater,AtomicLongFieldUpdater,AtomicReferenceFieldUp ...
- java并发编程(十二)----(JUC原子类)数组类型介绍
上一节我们介绍过三个基本类型的原子类,这次我们来看一下数组类型: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray.其中前两个的使用方 ...
- java并发编程笔记(八)——死锁
java并发编程笔记(八)--死锁 死锁发生的必要条件 互斥条件 进程对分配到的资源进行排他性的使用,即在一段时间内只能由一个进程使用,如果有其他进程在请求,只能等待. 请求和保持条件 进程已经保持了 ...
- java并发编程笔记(七)——线程池
java并发编程笔记(七)--线程池 new Thread弊端 每次new Thread新建对象,性能差 线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多系统资源导致死机或者OOM 缺 ...
- java并发编程笔记(六)——AQS
java并发编程笔记(六)--AQS 使用了Node实现FIFO(first in first out)队列,可以用于构建锁或者其他同步装置的基础框架 利用了一个int类型表示状态 使用方法是继承 子 ...
- java并发编程笔记(五)——线程安全策略
java并发编程笔记(五)--线程安全策略 不可变得对象 不可变对象需要满足的条件 对象创建以后其状态就不能修改 对象所有的域都是final类型 对象是正确创建的(在对象创建期间,this引用没有逸出 ...
- java并发编程笔记(三)——线程安全性
java并发编程笔记(三)--线程安全性 线程安全性: 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现 ...
- java并发编程笔记(十一)——高并发处理思路和手段
java并发编程笔记(十一)--高并发处理思路和手段 扩容 垂直扩容(纵向扩展):提高系统部件能力 水平扩容(横向扩容):增加更多系统成员来实现 缓存 缓存特征 命中率:命中数/(命中数+没有命中数) ...
- java并发编程笔记(十)——HashMap与ConcurrentHashMap
java并发编程笔记(十)--HashMap与ConcurrentHashMap HashMap参数 有两个参数影响他的性能 初始容量(默认为16) 加载因子(默认是0.75) HashMap寻址方式 ...
随机推荐
- linkin大话面向对象--包和导入
我们现在的代码都扔在一个文件夹里面,比如以后我们做项目,是不是有可能有非常非常多的代码,那我就希望把不同功能和模块的类方便管理,放到不同的文件夹下,引出包概念. 什么是包,就一个文件目录,为了处理重名 ...
- 常用的几个PHP加密函数
1.前言 PHP加密方式分为单项散列加密,对称加密,非对称加密这几类. 像常用的MD5.hash.crypt.sha1这种就是单项散列加密,单项散列加密是不可逆的. 像URL编码.base64编码这种 ...
- VUE-脚手架搭建
1.什么vue-cli vue-cli是vue.js的脚手架,用于自动生成vue.js工程模板的. 步骤: 2.安装 ->全局安装 npm install vue-cli -g 或 ...
- 使用命令行生成jar包
测试用类 public class Hello { public static void main(String[] args) { System.out.println("hello wo ...
- Effective Java 之-----for-each循环优于传统的for循环
如下代码: enum Face {1,2,3,4,5,6}: ...... Collection<Face> faces = Array.asList(Face.values); for( ...
- 覆盖equals()时总要覆盖hashCode()
覆写如下: public class User{ private Integer id; private String userName; private String passWord; publi ...
- Linux(CentOS)挂载NTFS格式的U盘、移动硬盘
以下操作均在root下执行的 1.U盘挂载 mkdir /mnt/usb //创建一个目录,用于挂载U盘 fdisk -l //查看系统中挂载的U盘,若系统有一块硬盘sdb1 代表你的U盘,/dev/ ...
- 第一个 HTML5Plus 移动应用
什么是 HTML5Plus 移动应用 HTML5 Plus移动App,简称5+App,是一种基于HTML.JS.CSS编写的运行于手机端的App,这种App可以通过扩展的JS API任意调用手机的原生 ...
- 【AIX】AIX内存机制
[AIX]AIX内存机制 1 虚拟内存 虚拟内存是物理内存和交换空间(Paging Space)组合形成的虚拟内存空间, 通过虚拟的地址空间映射到物理内存或者 Paging Space. 在 AIX ...
- [实例]JAVA调用微信接口发送图文消息,不用跳到详情页
package com.test; import java.io.IOException; import java.io.InputStream; import java.io.OutputStrea ...