励精图治---Concurrency---利用线程安全类来构建

委托是创建线程安全模块最有效的策略。


注意几个要点:

1. 利用委托来确保线程安全----新建一个类,调用非线程安全类的接口,在新建类中完善同步

2. 注意同步时加锁的对象。不可弄错了同步对象

3. 利用clone,将对象复制出来后,修改这个副本,修改完成后,重定向。(这可能伴随着开销问题)

        在clone过程中也要加锁。

4. 要注意多线程操作时,不能存在持有锁过长的行为。这将导致吞吐量严重降低

5. 利用ConcurrentModificationException。抛出异常

6. 并发的实现是一个增强一部分功能,削弱一部分功能的过程。有得有失。

7. 在多线程环境下,通过并发容器来代替同步容器,可以提高吞吐量。并发是一种权衡!



HashMap与ConcurrentHashMap

两者的区别是一个是线程安全,一个是线程非安全。

ConcurrentHashMap的加锁机制:分段所。粒度更小。让一定数量的线程可以并发的进行读写。

这种并发,加强了读写,削弱了统计。比如size,isEmpty。


CopyOnWriteArrayList

这个类是在进行操作的时候先复制一个副本出来,然后利用这个副本操作,操作完成后,重定向.

特点:在操作时候(包括add remove set),会调用System.arraycopy,这个导致每次操作的都是不同的引用.避免了java.util.ConcurrentModificationException.同时也付出了性能的代价,这个类不适合经常进行重复的操作.性能消耗太大...

换言之,这个类除了是线程安全的.其他的也没觉得吞吐量有大的改变.反而消耗了性能.


生产者消费者模式

队列有两种,有界队列和无界队列.

无界队列:put操作无阻塞.但是消耗可能会一直增加.导致资源过度负荷

有界队列:有阻塞,但能防止资源过度负荷.!!!即便是超载了.也可以利用offer方法(若数据无法添加则返回失败状态), 通过将工作序列化的手段,写入磁盘,待后续再操作!!!

这里要特别注意有界队列的使用, 它能抑制产生过多的工作项, 使程序在过载的情况下更加强健.


现成类的利用

BlockingQueue支持任意数量的生产者和消费者.

BlockingQueue的多种实现

LinkedBlockingQueue: FIFO

ArrayBlockingQueue: FIFO

PriorityBlockingQueue: 优先级排序

SynchronousQueue: 快速处理模型,没有中间存储.

特点:1. 不允许null元素

2. 阻塞队列,每个put都需要等待一个get

3. 队列容量为0, size方法只有恰巧有放入的时候去读了一下,才能读取到一个1 否则都是0.

4. 线程安全

5. FIFO


对象池

对象池使用的基本思路是:将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用,从而在一定程度上减少频繁创建对象所造成的开销。 并非所有对象都适合拿来池化――因为维护对象池也要造成一定开销。对生成时开销不大的对象进行池化,反而可能会出现“维护对象池的开销”大于“生成新对象的开销”,从而使性能降低的情况。但是对于生成时开销可观的对象,池化技术就是提高性能的有效策略了。


双端队列

在生产者消费者模式中,每个消费者都有一个双端队列.如果消费者完成了自己的任务,就可以从其他线程中去取.因为是双端队列,所以也不会影响到其他线程.

意义在于让线程尽可能的全部工作,增加效率.


同步工具类
1. 闭锁:一次性,结束后无法重置.适用: 确保某个服务在其他服务启动后在启动, 确保否个操作在其他资源初始化后在操作, 等待所有的参与者都到期了再操作.

       实现类:CountDownLatch.java

2. FutureTask:采用Executor框架,异步操作.提前计算某些  高开销操作.

3. 信号量:semaphore--->可用来实现资源池.

4. 栅栏:cyclicBarrier:用在迭代算法, 将一个重复的计算,分成多个子问题,每个子问题分配一个线程进行操作.

Exchange:意在提高应用程序响应时间,

这部分,因为我也没用到过.就不详细看了.知道就好.关键是要知道有这个东西.到时候去查一下.就知道了


高效可伸缩缓存程序

范例:

public interfaceComputable<A, V> {

V compute(A arg) throws InterruptedException;

}


public class ExpensiveFunction implements Computable<String, BigInteger> {

public BigInteger compute(String arg){

return new BigInteger(arg);

}

}


public class Memoizer1<A, V> implements Computable<A, V> {

@GuardedBy("this")

private final Map<A, V> cache = new HashMap<A, V)();

private final Computable<A,V> c;


public Memoizer1(Computable<A, V> c){

this.c = c;

}


public synchronized V compute(A arg) throws InteruptedException {--------------->多线程环境下,函数加锁,会让并发性减弱

V result = cache.get(arg);

if (result == null) {

result = c.compute(arg);

cache.put(arg.result);

}

return result;

}

}


修改1



public class Memoizer1<A, V> implements Computable<A, V> {

@GuardedBy("this")

private final Map<A, V> cache = new ConcurrentHashMap<A, V)();--->从HashMap改成ConcurrentHashMap,增强并发性

private final Computable<A,V> c;


public Memoizer1(Computable<A, V> c){

this.c = c;

}


public V compute(A arg) throws InteruptedException {--------------->去掉synchronized,提高并发性

V result = cache.get(arg);

if (result == null) {

result = c.compute(arg);---->这里可以被并入,因为result可以被同时判断成null,存在计算相同数值的风险

cache.put(arg.result);

}

return result;

}

}


修改2

public class Memoizer1<A, V> implements Computable<A, V> {

@GuardedBy("this")

private final Map<A, V> cache = new ConcurrentHashMap<A, Future<V>)();--->V改成Future<V>,加入线程是否启动计算的判断,大幅降低重复计算率

private final Computable<A,V> c;


public Memoizer1(Computable<A, V> c){

this.c = c;

}


public V compute(A arg) throws InteruptedException {

Future<V> f = cache.get(args);

if(f == null){

Callable<V> eval = new Callable<V>() {

public V call() throws InteruptedException {

return c.compute(args);

}

}

FutureTask<V> ft = new FutureTask<V> (eval);

f = ft;

cache.put(arg, ft);---------->先保存了状态,大幅降低了重复计算。除非同时又在这里重复了。

ft.run();---->可以开始compute计算

}------->将result = c.compute(arg),改成这么一串代码,

try {

return f.get();

}catch(ExcutionException e) {

throw launderThrowable(e.getCause());

}

}

}



修改3.

public class Memoizer1<A, V> implements Computable<A, V> {

@GuardedBy("this")

private final Map<A, V> cache = new ConcurrentHashMap<A, Future<V>)();

private final Computable<A,V> c;


public Memoizer1(Computable<A, V> c){

this.c = c;

}


public V compute(A arg) throws InteruptedException {

Future<V> f = cache.get(args);

if(f == null){

Callable<V> eval = new Callable<V>() {

public V call() throws InteruptedException {

return c.compute(args);

}

}

FutureTask<V> ft = new FutureTask<V> (eval);

f = cache.putIfAbsent(arg, ft);----------->这里再加入重复计算判断。避免之前加过一次。这次就彻底杜绝了。

if (f == null){

f = ft;

ft.run();

}

}

try {

return f.get();

}catch(ExcutionException e) {

throw launderThrowable(e.getCause());

}

}

}

这个流程很有意思。不断的对状态变量进行判断压缩,提高安全系数。

public class Memoizer1<A, V> implements Computable<A, V> {

@GuardedBy("this")

private final Map<A, V> cache = new HashMap<A, V)();

private final Computable<A,V> c;


public Memoizer1(Computable<A, V> c){

this.c = c;

}


public synchronized V compute(A arg) throws InteruptedException {--------------->多线程环境下,函数加锁,会让并发性减弱

V result = cache.get(arg);

if (result == null) {

result = c.compute(arg);

cache.put(arg.result);

}

return result;

}

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值