//第一版
package com.hra.riskprice; import com.hra.riskprice.SysEnum.Factor_Type;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import javax.swing.text.html.HTMLDocument;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit; class ForwardingSet<E> implements Set<E>{
private final Set<E> s;
public ForwardingSet(Set<E> s){this.s=s;} @Override
public void clear() {
s.clear();
} public boolean isEmpty(){return s.isEmpty();}
public int size(){return s.size();}
public Iterator<E> iterator(){return s.iterator();}
public boolean add(E e){return s.add(e);}
public boolean remove(Object o){return s.remove(o);}
public boolean containsAll(Collection<?> c){return s.containsAll(c);}
public boolean addAll(Collection<? extends E> c){
return s.addAll(c);
}
public boolean removeAll(Collection<?> c){
return s.removeAll(c);
}
public boolean retainAll(Collection<?> c){
return s.retainAll(c);
} @Override
public Object[] toArray() {
return s.toArray();
} @Override
public <T> T[] toArray(T[] a) {
return s.toArray(a);
} @Override
public boolean equals(Object o) {
return s.equals(o);
} @Override
public int hashCode() {
return s.hashCode();
} @Override
public String toString() {
return s.toString();
} @Override
public boolean contains(Object o) {
return s.contains(o);
}
} interface SetObserver<E>{ void added(ObservableSet<E> set,E element);
} class ObservableSet<E> extends ForwardingSet<E>{ public ObservableSet(Set<E> set){
super(set);
} private final List<SetObserver<E>> observers=new ArrayList<SetObserver<E>>(); public void addObserver(SetObserver<E> observer){
synchronized(observers){
observers.add(observer);
}
}
public boolean removeObserver(SetObserver<E> observer){
synchronized (observers){
return observers.remove(observer);
}
}
public void notifyElementAdded(E element){
synchronized (observers){
for(SetObserver<E> observer:observers){
observer.added(this,element);
}
}
} @Override
public boolean add(E e) {
boolean added=super.add(e);
if(added){
notifyElementAdded(e);
}
return added;
} @Override
public boolean addAll(Collection<? extends E> c) {
boolean result=false;
for(E element:c){
result|=add(element);
}
return result;
}
} @SpringBootApplication
public class RiskpriceApplication { public static void main(String[] args) { ObservableSet<Integer> set=new ObservableSet<Integer>(new HashSet<Integer>());
set.addObserver(new SetObserver<Integer>() {
@Override
public void added(ObservableSet<Integer> s, Integer e) {
System.out.println(e);
if(e==){
s.removeObserver(this);
}
}
});
for(int i=;i<;i++){
set.add(i);
}
}
}
你觉得会打印0~23吗,实际上运行后就挂了,for循环遍历过程中,不允许修改枚举列表,我们可以考虑通过另外一个线程去移除这个观察者,也是下面过度得第二版了 通过 ExecutorService //第二版
package com.hra.riskprice; import com.hra.riskprice.SysEnum.Factor_Type;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import javax.swing.text.html.HTMLDocument;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; class ForwardingSet<E> implements Set<E>{
private final Set<E> s;
public ForwardingSet(Set<E> s){this.s=s;} @Override
public void clear() {
s.clear();
} public boolean isEmpty(){return s.isEmpty();}
public int size(){return s.size();}
public Iterator<E> iterator(){return s.iterator();}
public boolean add(E e){return s.add(e);}
public boolean remove(Object o){return s.remove(o);}
public boolean containsAll(Collection<?> c){return s.containsAll(c);}
public boolean addAll(Collection<? extends E> c){
return s.addAll(c);
}
public boolean removeAll(Collection<?> c){
return s.removeAll(c);
}
public boolean retainAll(Collection<?> c){
return s.retainAll(c);
} @Override
public Object[] toArray() {
return s.toArray();
} @Override
public <T> T[] toArray(T[] a) {
return s.toArray(a);
} @Override
public boolean equals(Object o) {
return s.equals(o);
} @Override
public int hashCode() {
return s.hashCode();
} @Override
public String toString() {
return s.toString();
} @Override
public boolean contains(Object o) {
return s.contains(o);
}
} interface SetObserver<E>{ void added(ObservableSet<E> set,E element);
} class ObservableSet<E> extends ForwardingSet<E>{ public ObservableSet(Set<E> set){
super(set);
} private final List<SetObserver<E>> observers=new ArrayList<SetObserver<E>>(); public void addObserver(SetObserver<E> observer){
synchronized(observers){
observers.add(observer);
}
}
public boolean removeObserver(SetObserver<E> observer){
synchronized (observers){
return observers.remove(observer);
}
}
public void notifyElementAdded(E element){
synchronized (observers){
for(SetObserver<E> observer:observers){
observer.added(this,element);
}
}
} @Override
public boolean add(E e) {
boolean added=super.add(e);
if(added){
notifyElementAdded(e);
}
return added;
} @Override
public boolean addAll(Collection<? extends E> c) {
boolean result=false;
for(E element:c){
result|=add(element);
}
return result;
}
} @SpringBootApplication
public class RiskpriceApplication { public static void main(String[] args) throws InterruptedException{ ObservableSet<Integer> set=new ObservableSet<Integer>(new HashSet<Integer>());
set.addObserver(new SetObserver<Integer>() {
@Override
public void added(ObservableSet<Integer> s, Integer e) {
System.out.println(e);
if(e==){
ExecutorService excutor= Executors.newSingleThreadExecutor();
final SetObserver<Integer> observer=this;
try{
excutor.submit(new Runnable() {
@Override
public void run() {
s.removeObserver(observer);
}
}).get(); }catch (ExecutionException ex){
throw new AssertionError(ex.getCause());
}catch (InterruptedException ex){
throw new AssertionError(ex.getCause());
}finally {
excutor.shutdown();
}
}
}
});
for(int i=;i<;i++){
set.add(i);
}
}
}
第二版虽然会打印到23但是实际上并没有成功,
public void run() {
s.removeObserver(observer);
}
进入
public boolean removeObserver(SetObserver<E> observer){
synchronized (observers){
return observers.remove(observer);
} }
经过同步快synchronized 的时候将会遭遇死锁,因为主线程已经锁定了observers,只有等待子线程执行完成后才会释放锁,而子线程又在等待锁的释放,这样相互的等待就造成了死锁,但是由于Java设计的锁是可重入的,这种调用不会产生死锁,但会产生一个异常,因为调用线程正在该锁所保护的线程上进行着。这种失败可能是灾难性的,本质来说这个锁,没有尽到它的职责。可重入的锁简化了多线程的面向对象程序构造,但是它可能会将活性失败,变成安全性失败(参考自Effective java)
什么解决呢,来个2.1版本吧
我们建立个快照,而不使用原observers,这样每个通知都使用了自己的快照观察者列表引用就不会死锁了
public void notifyElementAdded(E element){
List<SetObserver<E>> snaphot=null;//快照
synchronized (observers){
snaphot=new ArrayList<SetObserver<E>>(observers);
}
for(SetObserver<E> observer:snaphot){
observer.added(this,element);
}
} //第三版
事实上,要将外来方法的调用移出同步代码块还有更好的方法,从java1.5发行版以来,提供了并发集合 corrent collection ,称作 CopyOnWriteArrayList,
这是专门为此定制的,他是Arraylist的一种变体,通过重新拷贝整个底层数组,在这里实现所有的操作,由于内部数组永远不动(归功于重新拷贝),因此迭代不需要锁定,大量使用有性能影响,但对于观察者列表几乎不变来说却是很好的,因为他们几乎不改动,并且经常遍历
第三版较之前2.1版本更改如下:
private final List<SetObserver<E>> observers=new CopyOnWriteArrayList<SetObserver<E>>(); public void addObserver(SetObserver<E> observer){
//synchronized(observers){
observers.add(observer);
//}
}
public boolean removeObserver(SetObserver<E> observer){
//synchronized (observers){
return observers.remove(observer);
//} }
public void notifyElementAdded(E element){
//List<SetObserver<E>> snaphot=null;//快照
//synchronized (observers){
// snaphot=new ArrayList<SetObserver<E>>(observers);
//}
for(SetObserver<E> observer:observers){
observer.added(this,element);
}
} 当然这个方法也可以改了,因为实际操作的时候底层是重新拷贝,所以也就不需要通过另外一个线程去移除引用了 修改如下:
set.addObserver(new SetObserver<Integer>() {
@Override
public void added(ObservableSet<Integer> s, Integer e) {
System.out.println(e);
if(e==){
s.removeObserver(this);
// ExecutorService excutor= Executors.newSingleThreadExecutor();
// final SetObserver<Integer> observer=this;
// try{
// excutor.submit(new Runnable() {
// @Override
// public void run() {
// s.removeObserver(observer);
// }
// }).get();
//
// }catch (ExecutionException ex){
// throw new AssertionError(ex.getCause());
// }catch (InterruptedException ex){
// throw new AssertionError(ex.getCause());
// }finally {
// excutor.shutdown();
// }
}
}
});

java 多线程 同步 观察者 并发集合的一个例子的更多相关文章

  1. Java多线程同步问题的探究

    一.线程的先来后到——问题的提出:为什么要有多线程同步?Java多线程同步的机制是什么? http://www.blogjava.net/zhangwei217245/archive/2010/03/ ...

  2. 转:关于JAVA多线程同步

    转:http://lanvis.blog.163.com/blog/static/26982162009798422547/ 因为需要,最近关注了一下JAVA多线程同步问题.JAVA多线程同步主要依赖 ...

  3. java多线程同步

    一篇好文:java多线程机制同步原则 概括起来说,Java 多线程同步机制主要包含如下几点:1:如果一个类包含一个或几个同步方法,那么由此类生成的每一个对象都配备一个队列用来容纳那些等待执行同步的线程 ...

  4. Java多线程-同步:synchronized 和线程通信:生产者消费者模式

    大家伙周末愉快,小乐又来给大家献上技术大餐.上次是说到了Java多线程的创建和状态|乐字节,接下来,我们再来接着说Java多线程-同步:synchronized 和线程通信:生产者消费者模式. 一.同 ...

  5. Java多线程专题1: 并发与并行的基础概念

    合集目录 Java多线程专题1: 并发与并行的基础概念 什么是多线程并发和并行? 并发: Concurrency 特指单核可以处理多任务, 这种机制主要实现于操作系统层面, 用于充分利用单CPU的性能 ...

  6. Java多线程同步问题:一个小Demo完全搞懂

    版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.一个简单的Demo引发的血案 关于线程同步问题我们从一个 ...

  7. Java多线程(六) —— 线程并发库之并发容器

    参考文献: http://www.blogjava.net/xylz/archive/2010/07/19/326527.html 一.ConcurrentMap API 从这一节开始正式进入并发容器 ...

  8. 聊聊Java里常用的并发集合

    前言 在我们的程序开发过程中,如果涉及到多线程环境,那么对于集合框架的使用就必须更加谨慎了,因为大部分的集合类在不施加额外控制的情况下直接在并发环境中直接使用可能会出现数据不一致的问题,所以为了解决这 ...

  9. Java 多线程同步和异步详解

    java线程 同步与异步 线程池 1)多线程并发时,多个线程同时请求同一个资源,必然导致此资源的数据不安全,A线程修改了B线 程的处理的数据,而B线程又修改了A线程处理的数理.显然这是由于全局资源造成 ...

随机推荐

  1. 使用setup.py安装python包和卸载python包的方法

    使用setup.py安装python包和卸载python包的方法 记录安装后文件的路径 python setup.py install --record files.txt删除这些文件 cat fil ...

  2. Ubuntu下三种方法设置环境变量

    一种用于当前终端,一种用于当前用户,一种用于所有用户: 用于当前终端: 在当前终端中输入:export PATH=$PATH:<你的要加入的路径> 不过上面的方法只适用于当前终端,一旦当前 ...

  3. SpringSecurity-UsernamePasswordAuthenticationFilter的作用

    UsernamePasswordAuthenticationFilter应该是我们最关注的Filter,因为它实现了我们最常用的基于用户名和密码的认证逻辑. 先看一下一个常用的form-login配置 ...

  4. jenkines的工作区目录位置查找

    先找到jenkines的主目录 系统-系统配置 然后工作区在主目录的workspace文件夹里面

  5. 廖雪峰Java7处理日期和时间-2Data和Calendar-1Date

    计算机中如何存储和表示日期和时间 Epoch Time:从1970年1月1日零点(格林威治时区/GMT+00:00)到现在经历的秒数,也叫timestamp, 例如: 秒级: * 北京 2016-11 ...

  6. 廖雪峰Java7处理日期和时间-1概念-1日期和时间

    1.日期 日期是指某一天,如2016-11-20,2018-1-1 2.时间有2种: 不带日期的时间:14:23:54 带日期的时间:2017-1-1 20:21:23,唯一确定某个时刻 3.时区 时 ...

  7. [sharepoint]修改Item或者File的Author和Editor

    写在前面 最近项目中调用sharepoint rest api方式获取文件或者Item列表,而用的方式是通过证书请求,在上传文件,或者新建item的时候,默认的用户是在sharepoint端注册的用户 ...

  8. IDEA查看类继承关系及生成类关系图

    1.在想要查看的类上按 Ctrl + H -> Diagrams -> Show Diagrams -> Java Class Diagrams -> Show Impleme ...

  9. Requests对HTTPS请求验证SSL证书

    SSL证书通过在客户端浏览器和Web服务器之间建立一条SSL安全通道(Secure socket layer(SSL)安全协议是由Netscape Communication公司设计开发.该安全协议主 ...

  10. eShopOnContainers 看微服务 ②:配置 启动

    一.什么是docker Docker 是一个开源项目,通过把应用程序打包为可移植的.自给自足的容器(可以运行在云端或本地)的方式,实现应用程序的自动化部署. 使用 Docker 的时候,需要创建一个应 ...