Java 6-5:拒绝3P,拒绝黄赌毒!——安全性失败,同步访问
来源:互联网 发布:行知实验中学 编辑:程序博客网 时间:2024/05/17 20:22
首先需要注意的是同步访问会让并行变为串行,但安全和效率,这两个之间没有折衷,安全第一,但我们要追求的必须是高效安全
- 本文涉及到:
- 原子操作
- 临界区
- 锁
- 信号量
因为并发的访问共享资源导致状态不一致造成的安全问题,就叫安全性失败,我们通过同步化访问来解决。
1 共享受限资源
什么时候会出现共享受限资源的冲突?
有一份数据摆在这里,多个worker线程都对其进行修改,状态就可能会乱了
总之,每次访问一个资源时,从进去到出来,都要保证数据的一致性
基本上所有保护共享受限资源的方法,都是序列化对受限资源的访问(同步化),也就是程序到这里就变成串行了,加个锁保证同时只有一个线程访问,这种机制就叫互斥量
如果你改变一个对象的状态是一个复杂的过程:
* 这期间你最好保证不要出现任何被打断的可能
2 原子类
原子操作被用来写无锁的代码,避免同步
原子操作不是同步化的,而是避免了同步化:
——普通的运算操作,如果要依赖原子性,要谨慎使用,至少编程思想里不推荐的,除非非常懂JVM,能编写JVM,编程思想就是这个意思
——但是可以使用Atom系列类来保证安全
有两部分内容:
——普通的运算操作的原子性,如加减乘除,这个很难搞懂,你知道a+b是不是原子操作?
——Atom系列类,提供了一套原子操作,基本还是有保障的
2.1 原子操作
普通运算的原子性:暂时不做研究了
a++不是原子操作
+-*/也不是原子操作
x = x + 1 =也不是原子操作
想了解更多,再看一遍编程思想
2.2 原子类
原子类是可以信赖的,可以用来做性能调优,避免写同步代码,避免序列化访问资源
public class EvenGenerator extends IntGenerator { private int currentEvenValue = 0; public int next() { ++currentEvenValue; // Danger point here! ++currentEvenValue; return currentEvenValue; } public static void main(String[] args) { EvenChecker.test(new EvenGenerator()); }}
原子操作就是一步能完成的操作:
AtomicInteger currentEvenValue = new AtomicInteger(0);return currentEvenValue.addAndGet(2); //这里给value增加了2,并返回其值
注意:
- 说是原子操作被用来构建Concurrent包,不建议你用
- 用了原子操作,就省了很多加锁操作
都有什么
- AtomicInteger
- AtomicLong
- AtomicReference
3 Synchronized临界区
例子:
public class SynchronizedEventGenerator extends IntGenerator { private int currentEvenValue = 0; public int next() { synchronized (this) { ++currentEvenValue; ++currentEvenValue; return currentEvenValue; } } public static void main(String[] args) { EvenChecker.test(new SynchronizedEventGenerator()); }}
public synchronized int next() { ++currentEvenValue; // Danger point here! ++currentEvenValue; return currentEvenValue;}相当于:public int next() { synchronized (this) { ++currentEvenValue; ++currentEvenValue; return currentEvenValue; }}
synchronized的锁始终是加在一个对象上
- 直接修饰一个方法时,就是this
- 如果多个对象访问同一资源,锁就得加到一个外部的静态对象上
- 作用于静态方法/属性时,锁住的是存在于永久的Class对象
synchronized的原理:
- 每个object对象都有一个内置的锁
- 所有对象都自动含有单一的锁,JVM负责跟踪对象被加锁的次数
- 在任务(线程)第一次给对象加锁的时候, 计数变为1
- 每当这个相同的任务(线程)在此对象上获得锁时,计数会递增
- 只有首先获得锁的任务(线程)才能继续获取该对象上的多个锁
- 每当任务离开时,计数递减,当计数为0的时候,锁被完全释放
- 在HotSpot中JVM实现中,锁有个专门的名字:对象监视器
- 更深入的讲:
- 当多个线程同时请求某个对象监视器时,对象监视器会设置几种状态用来区分请求的线程
- Contention List:所有请求锁的线程将被首先放置到该竞争队列,是个虚拟队列,不是实际的Queue的数据结构
- Entry List:EntryList与ContentionList逻辑上同属等待队列,ContentionList会被线程并发访问,为了降低对 ContentionList队尾的争用,而建立EntryList
- Contention List中那些有资格成为候选人的线程被移到Entry List
- Wait Set:那些调用wait方法被阻塞的线程被放置到Wait Set
- OnDeck:任何时刻最多只能有一个线程正在竞争锁,该线程称为OnDeck
注意:
wait,notify和synchronized的用法
4 锁
import java.util.concurrent.locks.*;public class MutexEvenGenerator extends IntGenerator { private int currentEvenValue = 0; private Lock lock = new ReentrantLock(); public int next() { lock.lock(); try { ++currentEvenValue; Thread.yield(); // Cause failure faster ++currentEvenValue; return currentEvenValue; } finally { lock.unlock(); } } public static void main(String[] args) { EvenChecker.test(new MutexEvenGenerator()); }}
比synchronized多了什么特性:
——可以尝试获取锁,不必非得阻塞在这
——提供了比synchronized更细粒度的控制
——在实现链表遍历节点时,有个节点传递的加锁机制(锁耦合),在释放这个节点的锁之前,必须捕获下个节点的锁
——synchronized引起的阻塞无法被interrupt方法中断,但ReentrantLock提供了可以被中断的机制
——ReentrantLock.lockInterruptly():如果得不到锁(被其他地方占用),就会阻塞,但是这个阻塞可以被interrupt()
例子:
import java.util.concurrent.*;import java.util.concurrent.locks.*;public class AttemptLocking { private ReentrantLock lock = new ReentrantLock(); public void untimed() { boolean captured = lock.tryLock(); try { System.out.println("tryLock(): " + captured); } finally { if (captured) lock.unlock(); } } public void timed() { boolean captured = false; try { captured = lock.tryLock(2, TimeUnit.SECONDS); } catch (InterruptedException e) { throw new RuntimeException(e); } try { System.out.println("tryLock(2, TimeUnit.SECONDS): " + captured); } finally { if (captured) lock.unlock(); } } public static void main(String[] args) { final AttemptLocking al = new AttemptLocking(); al.untimed(); // True -- lock is available al.timed(); // True -- lock is available // Now create a separate task to grab the lock: new Thread() { { setDaemon(true); } public void run() { al.lock.lock(); System.out.println("acquired"); } }.start(); Thread.yield(); // Give the 2nd task a chance try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } al.untimed(); // False -- lock grabbed by task al.timed(); // False -- lock grabbed by task }} /* * Output: tryLock(): true tryLock(2, TimeUnit.SECONDS): true acquired * tryLock(): false tryLock(2, TimeUnit.SECONDS): false */// :~
boolean captured = lock.tryLock();//不会阻塞,不管有没有得到锁,都往下执行captured = lock.tryLock(2, TimeUnit.SECONDS); //会阻塞2秒,然后不管有没有得到锁,都往下执行
其他锁
其他高级锁,不好意思,我还没研究过
4 信号(Semaphore)
这个,也不好意思,我也没研究过
- Java 6-5:拒绝3P,拒绝黄赌毒!——安全性失败,同步访问
- 网络直播内容审核:拒绝黄拒绝赌拒绝黄赌毒!
- 附加sql数据库失败:拒绝访问 5
- SC OpenService 失败5:拒绝访问
- SC OpenService 失败5:拒绝访问
- SC OpenService 失败5:拒绝访问
- java基础—java.io.FileNotFoundException: E:\AAA(拒绝访问。)
- win7(家庭普通版)安装svn服务 [sc] openSCManager 失败 5 拒绝 访问拒绝
- win7安装svnserver服务 [sc] openSCManager 失败 5 拒绝 访问拒绝
- win7安装svn服务 [sc] openSCManager 失败 5 拒绝 访问拒绝
- SVN异常处理——提交失败:txn-current-lock:拒绝访问
- CScript 错误: 加载设置失败(拒绝访问)
- 创建IPC端口失败:拒绝访问
- VS2015 调试失败 提示拒绝访问解决方法
- Java:1拒绝访问问题
- java.io.IOException: 拒绝访问
- 拒绝访问
- 发生错误 5,拒绝访问
- Java 6-4:别看了,坑的就是你——活性失败-volatile
- CentOS6.8鼠标、键盘、SSH都不能用了!
- 原创jQuery插件之fakeimg
- 创建并运行maven项目
- JavaGUI实现点名系统
- Java 6-5:拒绝3P,拒绝黄赌毒!——安全性失败,同步访问
- ubuntu 修复grub引导 与windows共存
- oracle学习之:管理还原数据(undo)
- Java 6-6:你存的不只有.avi——ThreadLocal-线程本地存储
- 用gitbash将项目代码上传到GitHub
- home目录空间不足,cache占用空间太大
- Linux安装oracle11gR2官方步骤
- JQuery操作对象的属性
- 关于yourphp内容管理系统开启伪静态之后volist调用排序