并发编程的3个重要概念

1.原子性:

一个操作或者多个操作,要么全部成功,要么全部失败

1.java中保证了基本数据类型的读取和赋值,保证了原子性,这些操作不可终端

a=10  原子性
b=a 不满足 1.read a; 2.assign b;
c++ 不满足 1.read c; 2 add 3.assige to c
c=c+1 不满足 1.read c 2.add; 3. assign to c;

2.可见性:

volatile 可以保证可见性.主要是把变量放在主存里

多个线程访问这个变量,一个线程修改之后必须保证另一个线程可以看见。

每一个线程都自己的缓存,有的变量在主存区,我们要保证变量的可见性

4.顺序性:

java中hapens-before 原则保证了有序性

4.1 代码顺序(程序顺序规则): 单个线程中的每个操作    编写在前面的反生在编写在后面的

4.2 lock原则(监视器锁规则) : unlock 必须发生在lock之后

4.3 volatile变量规则: 对该变量的写操作必须发生在读操作之前.就是一个变量 写变量发生在读变量之前

4.4 传递规则: a->b->c  那么a肯定在c之前

4.5 start规则:   先start 线程在启动(个人认为废话)

4.6 中断规则: 对线程的中断 先发生在 捕获interpetor异常之前(个人认为废话)

4.7 对象的销毁规则: 一个对象的初始化.必须发生在finalize 之前(个人认为废话)

4.8 线程的终结规则: 所有操作都发生在线程死亡之前 (个人认为废话)

比如定义一个变量

int i =0;

boolean flag =false;

int i =1;

boolean flag =true;

java中有重排序的过程 因为这几条代码没有关联性可能会变成

int i =0;

boolean flag =false;

boolean flag =true;

int i =1;

重排序只保证最终一致性,重排序也是有依赖关系的,重排序对没有依赖关系的可以重排序 ,重排序不会影响单线程,但是会影响多线程

举个例子

--------thread-1 ==========

obj =createObj();1
flag = true; 2
如果这里发生指令重排将  1 -2 顺序颠倒下面下面的代码就会报出空指针异常

-----thread-2------
while(!flag){
}
useObject()

atomic 具有原子性

主要有俩点 1.他的变量是volatile

       2.unsafe方法调用

    // setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset; static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
} private volatile int value;

什么时候需要使用atomic类对象

当多线程操作一个变量的时候。如果使用传统的变量会出错,很多同学为了解决这个问题,加了votatile修饰。也并不能够解决问题。

补充下votalite 的知识

volatile具有可见性、有序性,不具备原子性。

当value+=1时候我们需要做几个操作

1.从主存区获取变量到写存区

2.value+1

3.value = 新的value

4.讲变量写入主存区  

这4步都是原子性的。但是在多线程环境中。可能你读取到的变量是别人修改过的变量造成线程不安全情况  

  private static Set<Integer> set = Collections.synchronizedSet(new HashSet<>());

    public static void main(String[] args) throws InterruptedException {

       Thread t1= new Thread(()->{
int x=0;
while (x<500){
set.add(value);
int temp =value;
System.out.println(Thread.currentThread().getName()+" "+temp);
value +=1;
x++; }
});
Thread t2= new Thread(()->{
int x=0;
while (x<500){
set.add(value);
int temp =value;
System.out.println(Thread.currentThread().getName()+" "+temp);
value +=1;
x++; }
});
Thread t3= new Thread(()->{
int x=0;
while (x<500){
set.add(value);
int temp =value;
System.out.println(Thread.currentThread().getName()+" "+temp);
value +=1;
x++; }
}); t1.start();
t2.start();
t3.start();
t1.join(); t2.join(); t3.join();
System.out.println(set.size());

当我们使用aomic类时。可以保证原子性

     AtomicInteger atoValue = new AtomicInteger();
Thread t1= new Thread(()->{
int x=0;
while (x<500){
int i = atoValue.getAndIncrement();
set.add(i);
System.out.println(Thread.currentThread().getName()+" "+i);
atoValue.getAndIncrement();
x++; }
});
Thread t3= new Thread(()->{
int x=0;
while (x<500){
int i =atoValue.getAndIncrement();
set.add(i);
System.out.println(Thread.currentThread().getName()+" "+i);
atoValue.getAndIncrement();
x++; }
});
Thread t2= new Thread(()->{
int x=0;
while (x<500){
int i = atoValue.getAndIncrement();
set.add(i);
System.out.println(Thread.currentThread().getName()+" "+i); x++; }
});
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
System.out.println(set.size());

下载jdk源码

http://download.java.net/openjdk/jdk8/promoted/b132/openjdk-8-src-b132-03_mar_2014.zip

源码查看

/openjdk/jdk/src/share/classes/sun/misc/Unsafe.java

atomic保证原子性操作是因为有unsafe.java

很多人都说unsafe.java 是java留的一后门可以直接操作cpu级别的内存

因为UnSafe提供了硬件级别的原子操作,提高了Java对底层操作的能力。Unsafe类使Java语言拥有了像C语言的指针一样的操作内存空间的能力

一篇比较好的博客

https://www.cnblogs.com/pkufork/p/java_unsafe.html

如何保证原子性

/**
* Atomically adds the given value to the current value of a field
* or array element within the given object <code>o</code>
* at the given <code>offset</code>.
*
* @param o object/array to update the field/element in
* @param offset field/element offset
* @param delta the value to add
* @return the previous value
* @since 1.8
*/
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
  1、需要修改的对象
2、更改属性的内存偏移量 4、要添加的 1
public final int getAndAddInt(Object o, long offset, int delta) { 
int v; do {
  v = getIntVolatile(o, offset);
} while (!compareAndSwapInt(o, offset, v, v + delta)); return v;
}
其实主要原子性是通过compareAndSwapInt对比算法.传入你开始的值.和预期的值 如果不相同就一直执行下去直到相同为止,达到很多人说的无锁概念,其实我更倾向于自旋锁
假设多线程调用getAndIncrement
假设初始值是1
compareAndWapInt(1,1+1)
compareAndWapInt(1,1+1)

1 2 比较false

进行下一次 2==2

2

1 2比较 false

2 3 比较false

3

这样就实现了free lock

获取unsafe.实例利用java反射

   Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);

自己测试类

  public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

         Field f1 = Unsafe.class.getDeclaredField("theUnsafe");
f1.setAccessible(true);
Unsafe unsafe = (Unsafe) f1.get(null);
Class clazz = Target.class;
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
// 获取属性偏移量,可以通过这个偏移量给属性设置
System.out.println(f.getName() + ":" + unsafe.objectFieldOffset(f));
}
Target target = new Target();
Field intFiled = clazz.getDeclaredField("intParam") ;
// int a=(Integer)intFiled.get(target ) ;
// System.out.println("原始值是:"+a);
//intParam的字段偏移是12 原始值是3 我们要改为10
System.out.println(unsafe.compareAndSwapInt(target, 12, 3, 10));
int b=(Integer)intFiled.get(target) ;
System.out.println("改变之后的值是:"+b);
//
// //这个时候已经改为10了,所以会返回false
System.out.println(unsafe.compareAndSwapInt(target, 12, 3, 10));
//
// System.out.println(unsafe.compareAndSwapObject(target, 24, null, "5"));
} }
class Target {
int intParam=3;
long longParam;
String strParam;
String strParam2;
}
												

多线程atomicInteger的更多相关文章

  1. Java后端技术面试汇总(第二套)

    1.Java相关 • Arraylist与LinkedList默认空间是多少:• Arraylist与LinkedList区别与各自的优势List 和 Map 区别:• 谈谈HashMap,哈希表解决 ...

  2. 使用 AtomicInteger 进行计数(java多线程优化)

    通常,在我们实现多线程使用的计数器或随机数生成器时,会使用锁来保护共享变量.这样做的弊端是如果锁竞争的太厉害,会损害吞吐量,因为竞争的同步非常昂贵. volatile 变量虽然可以使用比同步更低的成本 ...

  3. 多线程爬坑之路-J.U.C.atomic包下的AtomicInteger,AtomicLong等类的源码解析

    Atomic原子类:为基本类型的封装类Boolean,Integer,Long,对象引用等提供原子操作. 一.Atomic包下的所有类如下表: 类摘要 AtomicBoolean 可以用原子方式更新的 ...

  4. 测试AtomicInteger与普通int值在多线程下的递增操作

    日期: 2014年6月10日 作者: 铁锚 Java针对多线程下的数值安全计数器设计了一些类,这些类叫做原子类,其中一部分如下: java.util.concurrent.atomic.AtomicB ...

  5. Java多线程之原子性 volatile、atomicInteger测试

    原文链接:http://www.cnblogs.com/zhengbin/p/5653051.html 一.补充概念 1.什么是线程安全性? <Java Concurrency in Pract ...

  6. 測试AtomicInteger与普通int值在多线程下的递增操作

    日期: 2014年6月10日 作者: 铁锚 Java针对多线程下的数值安全计数器设计了一些类,这些类叫做原子类,当中一部分例如以下: java.util.concurrent.atomic.Atomi ...

  7. Java:多线程,java.util.concurrent.atomic包之AtomicInteger/AtomicLong用法

    1. 背景 java.util.concurrent.atomic这个包是非常实用,解决了我们以前自己写一个同步方法来实现类似于自增长字段的问题. 在Java语言中,增量操作符(++)不是原子的,也就 ...

  8. [Java多线程]-J.U.C.atomic包下的AtomicInteger,AtomicLong等类的源码解析

    Atomic原子类:为基本类型的封装类Boolean,Integer,Long,对象引用等提供原子操作. 一.Atomic包下的所有类如下表: 类摘要 AtomicBoolean 可以用原子方式更新的 ...

  9. Java 多线程 - 原子操作AtomicInteger & CAS(Compare-and-Swap)

    原子类简介:https://www.cnblogs.com/stephen0923/p/4505902.html AtomicInteger 介绍: https://yuwenlin.iteye.co ...

随机推荐

  1. 部署MVC项目ManagedPipelineHandler报错

    "处理程序ExtensionlessUrlHandler-Integrated-4.0在其模块列表中有一个错误模块ManagedPipelineHandler": 解决方法:以管理 ...

  2. asp.net 在自己指定的文件夹下面弄个App.config来读取配置

    .注意首先你要在你的应用程序的根目录下面新建一个Config的文件夹,然后在你新建的Config文件夹下面建立一个MyApp.config文件,根据标准的App.config复制一个过来稍作修改就好, ...

  3. 使用cmd命令登录mysql数据库时报2013-Lost connection to MYSQL server at 'waiting for initial communication packet',system error:0

    [错误内容]:SQL Error (2013): Lost connection to MySQL server at 'waiting for initial communication packe ...

  4. java MD5 并发

    Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护.该算法的文件号为RFC 1321(R.Rives ...

  5. medusa爆破路由

    medusa –M http -h 192.168.10.1 -u admin -P /usr/share/wfuzz/ wordlist/fuzzdb/wordlists-user-passwd/p ...

  6. RocketMQ 自定义文件路径

    一 .1. 修改store路径2. 修改logs路径3. 修改rmq_bk_gc.log路径4. 修改rmq_srv_gc.log路径二 .1. 获取正确的rocketmq 源码2. 地址:https ...

  7. JAVA常见面试题及解答

    JAVA相关基础知识1.面向对象的特征有哪些方面 1.抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分,暂时 ...

  8. ServiceStack.Text json中序列化日期格式问题的解决

    标记: ServiceStack.Text,json,序列化,日期 在使用ServiceStack.Text的序列化为json格式的时候,当属性为datetime的时候,返回的是一个new date( ...

  9. MySQL 笔记整理(20) --幻读是什么,幻读有什么问题?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 20) --幻读是什么,幻读有什么问题? 我们先来看看表结构和初始化数据 ...

  10. 饿了么 PostgreSQL 优化之旅

    1. 架构演变 在O2O外卖领域,基于位置服务的需求越来越多,这就要求DB能够存储地理位置信息,而在开源数据库中,对空间地理数据支持比较好的要数PG的插件Postgis. 饿了么在使用PG的过程中,由 ...