多线程下的数据安全
2019-04-10 15:20
78 查看
前言
多线程下的线程安全,主要是由于无法控制线程的执行顺序,无法确定那个线程是先执行,是由CPU确定的,出现线程不安全的情况-》每次运行的结构都不相同(程序无法按照我们想要的结果)
下面是一个简单的多线程例子,来说明下多线程下的数据安全
[code]package com.el.jichu.thread.writerlock; import java.util.concurrent.atomic.AtomicInteger; /** * @Auther: roman.zhang * @Date: 2019/4/10 8:44 * @Version:V1.0 * @Description:LockDemo1 */ public class LockDemo1 { // private AtomicInteger atomicInteger=new AtomicInteger(0); private int i=0; public void add(){ i++; //atomicInteger.getAndIncrement(); } public static void main(String[] args) throws InterruptedException { LockDemo1 demo1 = new LockDemo1(); for(int i=0;i<2;i++){ new Thread(()->{ for(int j=0;j<10000;j++){ demo1.add(); } }).start(); } Thread.sleep(3000); // System.out.println("计算结果是:"+demo1.atomicInteger); System.out.println("计算结果是:"+demo1.i); } }
每次运行结果:
第一次:11783
第二次:12670
上面之所以出现这种情况,是多线程下,无法控制线程间的执行顺序,无法确定在执行完一个线程后(即完成一个整体操作后,再去执行另一个线程)。
解决方式
1.使用AtomicInterger 下面是AtomicInterger相关的类
直接上代码:
[code]package com.el.jichu.thread.writerlock; import java.util.concurrent.atomic.AtomicInteger; /** * @Auther: roman.zhang * @Date: 2019/4/10 8:44 * @Version:V1.0 * @Description:LockDemo1 */ public class LockDemo1 { private AtomicInteger atomicInteger=new AtomicInteger(0); //private int i=0; public void add(){ //i++; atomicInteger.getAndIncrement(); } public static void main(String[] args) throws InterruptedException { LockDemo1 demo1 = new LockDemo1(); for(int i=0;i<2;i++){ new Thread(()->{ for(int j=0;j<10000;j++){ demo1.add(); } }).start(); } Thread.sleep(3000); System.out.println("计算结果是:"+demo1.atomicInteger); //System.out.println("计算结果是:"+demo1.i); } }
使用AtomicInter就能保证每次得到我们想要的结果
2.使用synchronized这个方式,不在介绍,介绍一个功能更多的Lock
直接上代码:
[code]package com.el.jichu.thread.writerlock; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Auther: roman.zhang * @Date: 2019/4/10 8:44 * @Version:V1.0 * @Description:LockDemo1 */ public class LockDemo1 { //private AtomicInteger atomicInteger=new AtomicInteger(0); private int i=0; private Lock lock=new ReentrantLock(); public void add(){ lock.lock(); try { i++; } finally { lock.unlock(); } //i++; //atomicInteger.getAndIncrement(); } public static void main(String[] args) throws InterruptedException { LockDemo1 demo1 = new LockDemo1(); for(int i=0;i<2;i++){ new Thread(()->{ for(int j=0;j<10000;j++){ demo1.add(); } }).start(); } Thread.sleep(3000); // System.out.println("计算结果是:"+demo1.atomicInteger); System.out.println("计算结果是:"+demo1.i); } }
下面介绍下AtomicInteger的原理(CAS)
CAS (硬件语言) 即每个线程从内存中拿到值(称为当前值),以及想把内存值改为的目标值,每次去更新内存值时,都会将当前值与内存值比较,如果相同,则把内存值变为目标值。
使用CAS方式实现线程同步
[code]package com.el.jichu.thread.writerlock; import sun.misc.Unsafe; import java.lang.reflect.Field; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Auther: roman.zhang * @Date: 2019/4/10 8:44 * @Version:V1.0 * @Description:LockDemo1 */ public class LockDemo1 { //private AtomicInteger atomicInteger=new AtomicInteger(0); private int i=0; private Lock lock=new ReentrantLock(); static Unsafe unsafe=null; private static long valueOffset; static { //反射 try { Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); unsafe= (Unsafe) theUnsafe.get(null); //目标:通过unsafe去调用底层硬件原语 //无法直接操作内存,委屈求全,只能去通过对象中属性的偏移量,去修改值 valueOffset = unsafe.objectFieldOffset(LockDemo1.class.getDeclaredField("i")); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } public void add(){ ///使用CAS去实现同步 //为什么是个循环:因为CAS会失败,因此才会使用循环 int current ; do{ current=unsafe.getIntVolatile(this,valueOffset); }while(!unsafe.compareAndSwapInt(this,valueOffset,current,current+1)); /** * unsafe.compareAndSwapInt(当前对象,内存值,当前值,新值) */ /* lock.lock(); try { i++; } finally { lock.unlock(); }*/ //i++; //atomicInteger.getAndIncrement(); } public static void main(String[] args) throws InterruptedException { LockDemo1 demo1 = new LockDemo1(); for(int i=0;i<2;i++){ new Thread(()->{ for(int j=0;j<10000;j++){ demo1.add(); } }).start(); } Thread.sleep(3000); // System.out.println("计算结果是:"+demo1.atomicInteger); System.out.println("计算结果是:"+demo1.i); } }
AtomicXXX源码:
3.使用自定义锁,实现线程同步
手写锁代码
[code]package com.el.jichu.thread.writerlock; import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.ato 1fff8 mic.AtomicReference; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.LockSupport; /** * @Auther: roman.zhang * @Date: 2019/4/10 10:32 * @Version:V1.0 * @Description:CustomLock * 思路 * 1.没有获取锁的线程,如何让线程挂起,不在往下执行,等待其他线程释放锁。 * 2.释放锁之后,如何通知其他线程去获取锁 */ public class CustomLock implements Lock { //锁的拥有者 AtomicReference<Thread> owner=new AtomicReference<>(); //一个容器存储等待的线程 ConcurrentHashMap<Thread,Object> queue=new ConcurrentHashMap<>(); @Override public void lock() { while( !owner.compareAndSet(null,Thread.currentThread())){ //没有获取成功,则将该线程停下来 queue.put(Thread.currentThread(),""); //正在运行的线程进入停车场 LockSupport.park(); queue.remove(Thread.currentThread()); } } @Override public void unlock() { while(owner.compareAndSet(Thread.currentThread(),null)){//释放锁 //通知其他线程去park线程,继续去强锁 // Thread next=null; ConcurrentHashMap.KeySetView<Thread, Object> threads = queue.keySet(); for(Thread t:threads){ LockSupport.unpark(t); } } } @Override public void lockInterruptibly() throws InterruptedException { } @Override public boolean tryLock() { return false; } @Override public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { return false; } @Override public Condition newCondition() { return null; } }
测试代码
[code]package com.el.jichu.thread.writerlock; import java.util.concurrent.locks.Lock; /** * @Auther: roman.zhang * @Date: 2019/4/10 15:15 * @Version:V1.0 * @Description:LockDomo2 */ public class LockDomo2 { private int i; //private AtomicInteger atomicInteger=new AtomicInteger(0); private Lock customLock=new CustomLock(); public void add(){ customLock.lock(); try { i++; } finally { customLock.unlock(); } //atomicInteger.getAndIncrement(); } public static void main(String[] args) throws InterruptedException { LockDomo2 demo2 = new LockDomo2(); for(int i=0;i<2;i++){ new Thread(()->{ for(int j=0;j<10000;j++){ demo2.add(); } }).start(); } Thread.sleep(3000); // System.out.println("计算结果是:"+demo1.atomicInteger); System.out.println("计算结果是:"+demo2.i); } }
相关文章推荐
- [Java]Java多线程数据安全(同步线程的方法)
- 04.多线程--04.【多线程卖票出现的数据安全问题】【同步代码块基本用法和原理】
- 多线程访问共享数据的安全问题
- 多线程下数据安全
- CVI多线程数据保护(安全变量)
- 安卓学习第十四天:多线程的数据安全,线程同步,数组,类集框架
- 多线程数据安全问题与三种解决方式
- CVI多线程数据保护(多个线程操作同一安全变量)
- 再谈c#中多线程下的数据安全
- Java多线程环境下如何高效安全处理数据(输入输出流、文件、网络等)(一)
- 4g dtu 4G DTU 3G DTU 2G DTU煤矿安全生产传感器的数据采集GPRS DTU
- 中国政法大学数据安全与应用规范研究基地正式成立
- shiro安全框架扩展教程--设计数据对象校验器,如何防止xss以及csrf攻击
- 集群中多线程如何处理表中的数据的问题
- iOS安全攻防:Fishhook、数据保护API以及基于脚本实现动态库注入
- DSA数据安全隔离-源代码防泄密
- 多线程的那点儿事(之数据同步)
- 安全问题:大数据究竟能否“摆平”?
- Apache Eagle——eBay开源分布式实时Hadoop数据安全方案
- Hook Adobe Products For Data Protection (拦截adobe的产品,保护数据安全)