JDK1.2引入最有争议性的改变是将集合类默觉得不是Thread安全性的。

一、Collection Class的概述

1. 具有Threadsafe 的Collection Class:
java.util.Vector(List) 列表集合,通过索引操作。
java.util.Stack(List) 继承自Vector,提供LIFO的顺序操作push进入,pop出元素。
java.util.Hashtable(Map) 一个简单、无序的key与value的映射。
java.util.concurrent.ConcurrentHashMap 一个实现无序的map的类,比Hashtable使用更少的同步机制。
java.util.concurrent.CopyOnWriteArrayList  提供无同步的Iterator。
java.util.concurrent.ConcurrentLinkedQueue 无限的FIFO队列。

2. Thread-Notification Collection Class
java.util.concurrent包下的线程安全的Queue:
ArrayBlockingQueue:有限的FIFO队列。
LinkedBlockingQueue:能够有限或无限的FIFO 队列。
SynchronousQueue:有限的FIFO队列。一种堵塞队列,当中每一个插入操作必须等待还有一个线程的相应移除操作 ,反之亦然。
PriorityBlockingQueue:一个无界堵塞队列,它使用与类 PriorityQueue 同样的顺序规则,而且提供了堵塞获取操作。
DelayQueue:Delayed 元素的一个无界堵塞队列,仅仅有在延迟期满时才干从中提取元素。

二、同步与Collection Class


使用Vector确保线程安全性样例:
import java.util.*;

public class CharacterEventHandler {
private Vector listeners = new Vector(); public void addCharacterListener(CharacterListener cl) {
listeners.add(cl);
} public void removeCharacterListener(CharacterListener cl) {
listeners.remove(cl);
} public void fireNewCharacter(CharacterSource source, int c) {
CharacterEvent ce = new CharacterEvent(source, c);
CharacterListener[] cl = (CharacterListener[] )
listeners.toArray(new CharacterListener[0]);
for (int i = 0; i < cl.length; i++)
cl[i].newCharacter(ce);
}
}


使用非线程安全的ArrayList,使用synchronized method来确保线程安全的样例:
import java.util.*;

public class CharacterEventHandler {
private ArrayList listeners = new ArrayList(); public synchronized void addCharacterListener(CharacterListener cl) {
listeners.add(cl);
} public synchronized void removeCharacterListener(CharacterListener cl) {
listeners.remove(cl);
} public synchronized void fireNewCharacter(CharacterSource source, int c) {
CharacterEvent ce = new CharacterEvent(source, c);
CharacterListener[] cl = (CharacterListener[] )
listeners.toArray(new CharacterListener[0]);
for (int i = 0; i < cl.length; i++)
cl[i].newCharacter(ce);
}
}


使用非线程安全的ArrayList,使用synchronized 块来确保线程安全的样例:
import java.util.*;

public class CharacterEventHandler {
private ArrayList listeners = new ArrayList(); public void addCharacterListener(CharacterListener cl) {
synchronized(listeners) {
listeners.add(cl);
}
} public void removeCharacterListener(CharacterListener cl) {
synchronized(listeners) {
listeners.remove(cl);
}
} public void fireNewCharacter(CharacterSource source, int c) {
CharacterEvent ce = new CharacterEvent(source, c);
CharacterListener[] cl;
synchronized(listeners) {
cl = (CharacterListener[] )
listeners.toArray(new CharacterListener[0]);
}
for (int i = 0; i < cl.length; i++)
cl[i].newCharacter(ce);
}
}

复杂的同步
     使用线程安全的集合类,就不会出现不论什么的线程安全问题,比如:竞态条件吗?
     答案是否定的,依旧会出现故障,当一个方法中涉及两次对同一个集合进行多次操作时就可能出现异常。
import java.util.*;
import javax.swing.*;
import javax.swing.table.*; public class CharCounter {
public HashMap correctChars = new HashMap();
public HashMap incorrectChars = new HashMap();
private AbstractTableModel atm; public void correctChar(int c) {
synchronized(correctChars) {
Integer key = new Integer(c);
Integer num = (Integer) correctChars.get(key);
if (num == null)
correctChars.put(key, new Integer(1));
else correctChars.put(key, new Integer(num.intValue() + 1));
if (atm != null)
atm.fireTableDataChanged();
}
} public int getCorrectNum(int c) {
synchronized(correctChars) {
Integer key = new Integer(c);
Integer num = (Integer) correctChars.get(key);
if (num == null)
return 0;
return num.intValue();
}
} public void incorrectChar(int c) {
synchronized(incorrectChars) {
Integer key = new Integer(c);
Integer num = (Integer) incorrectChars.get(key);
if (num == null)
incorrectChars.put(key, new Integer(-1));
else incorrectChars.put(key, new Integer(num.intValue() - 1));
if (atm != null)
atm.fireTableDataChanged();
}
} public int getIncorrectNum(int c) {
synchronized(incorrectChars) {
Integer key = new Integer(c);
Integer num = (Integer) incorrectChars.get(key);
if (num == null)
return 0;
return num.intValue();
}
} public void addModel(AbstractTableModel atm) {
this.atm = atm;
}
}

三、生产者/消费者模式

    以分割不同组的Thread的请求来进行异步处理数据。生产者是产生须要被处理的请求的Thread。消费者是接受奈尔请求并予以对应的Thread。这样的模式提供了一种清楚的分类让Thread能有更好的设计且可以更easy地调试。
    仅仅需提供安全的方法从生产者传递数据给消费者,数据仅仅须要在生产者与消费者之间传递的非常短时间中确保线程安全性就可以。
    能够使用线程安全的集合类:vector、list、queue。

生产者:
import java.util.*;
import java.util.concurrent.*; public class FibonacciProducer implements Runnable {
private Thread thr;
private BlockingQueue<Integer> queue; public FibonacciProducer(BlockingQueue<Integer> q) {
queue = q;
thr = new Thread(this);
thr.start();
} public void run() {
try {
for(int x=0;;x++) {
Thread.sleep(1000);
queue.put(new Integer(x));
System.out.println("Produced request " + x);
}
} catch (InterruptedException ex) {
}
}
}

消费者:
import java.util.concurrent.*;

public class FibonacciConsumer implements Runnable {
private Fibonacci fib = new Fibonacci();
private Thread thr;
private BlockingQueue<Integer> queue; public FibonacciConsumer(BlockingQueue<Integer> q) {
queue = q;
thr = new Thread(this);
thr.start();
} public void run() {
int request, result;
try {
while (true) {
request = queue.take().intValue();
result = fib.calculateWithCache(request);
System.out.println("Calculated result of " + result + " from " + request);
}
} catch (InterruptedException ex) { }
}
}

    生产者与消费者是去耦的,生产者绝不会直接调用消费者。

四、使用Collection Class

使用哪个集合类最好呢?
使用没有同步化的集合类会有小小的性能提升。
对很多有竞争的算法,考虑改用并发的Collection
生产者/消费者考虑使用Queue替代集合类。
尽量降低同步的使用

Java 线程第三版 第八章 Thread与Collection Class 读书笔记的更多相关文章

  1. Java 线程第三版 第一章Thread导论、 第二章Thread的创建与管理读书笔记

    第一章 Thread导论 为何要用Thread ? 非堵塞I/O      I/O多路技术      轮询(polling)      信号 警告(Alarm)和定时器(Timer) 独立的任务(Ta ...

  2. Java 螺纹第三版 第一章Thread介绍、 第二章Thread创建和管理学习笔记

    第一章 Thread导论 为何要用Thread ? 非堵塞I/O      I/O多路技术      轮询(polling)      信号 警告(Alarm)和定时器(Timer) 独立的任务(Ta ...

  3. Java 线程第三版 第九章 Thread调度 读书笔记

    一.Thread调度的概述 import java.util.*; import java.text.*; public class Task implements Runnable { long n ...

  4. Java 线程第三版 第四章 Thread Notification 读书笔记

    一.等待与通知 public final void wait() throws InterruptedException      等待条件的发生. public final void wait(lo ...

  5. Java 线程第三版 第五章 极简同步技巧 读书笔记

    一.能避免同步吗? 取得锁会由于下面原因导致成本非常高:     取得由竞争的锁须要在虚拟机的层面上执行很多其它的程序代码.     要取得有竞争锁的线程总是必须等到锁被释放后. 1. 寄存器的效应 ...

  6. 精通正则表达式(第三版)——Mastering Regular Expressions,3rd Edition——读书笔记1

    基础知识介绍: 子表达式匹配 环视 引号内的字符串:"(^")*" 12小时制:(1[0123]|[1-9]):[0-5][0-9]*(am|pm) 24小时制:(([0 ...

  7. 精通正则表达式(第三版)—Mastering Regular Expressions,3rd Edition—读书笔记2

    1.肯定断言:必须匹配一个字符 排除型字符组:匹配未列出字符的字符组 2.范围表示法——列出范围内所有的字符 大多数情况下,不会影响执行速度.但是,某些实现方式不能完全优化字符组.所以,最好是有范围表 ...

  8. 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题

    调用同步锁的wait().notify().notifyAll()进行线程通信 看这个经典的存取款问题,要求两个线程存款,两个线程取款,账户里有余额的时候只能取款,没余额的时候只能存款,存取款金额相同 ...

  9. 疯狂java讲义 第三版 笔记

      java7新加特性: 0B010101  二进制数 int c=0B0111_1111;   数值中使用下划线分隔 switch 支持String类型   字符串常量放在常量池 String s0 ...

随机推荐

  1. YYmodel 郭耀源 底层分析

    http://www.tuicool.com/articles/meAzIny         YYModel 简介与使用 http://www.jianshu.com/p/663c7b608ff5 ...

  2. 《招聘一个靠谱的iOS》面试题参考答案(下)

    相关文章: <招聘一个靠谱的iOS>面试题参考答案(上) 说明:面试题来源是微博@我就叫Sunny怎么了的这篇博文:<招聘一个靠谱的 iOS>,其中共55题,除第一题为纠错题外 ...

  3. Android开源库集锦

    一.兼容类库 ActionBarSherlock : Action Bar是Android 3.0后才开始支持的,ActionBarSherlock是让Action Bar功能支持2.X后的所有平台, ...

  4. 总结前端JQ常用的一些操作手法(慢慢完善)

    1.实例化Js一个object对象,把它当做类来用,事例是操作url的参数 function GetRequestCondition() { var url = window.location.hre ...

  5. calc()函数的使用

    calc()函数算是css中的一个另类了,一般来说css都是直接确定的样式,而calc()函数却是可以动态计算,这和css静态的概念有些区别,但这并不妨碍其优秀的性能. 什么是calc()? calc ...

  6. uva 1596 Bug Hunt

    In this problem, we consider a simple programming language that has only declarations of one-dimensi ...

  7. LP64是什么意思

    在64位机器上,如果int是32位,long是64位,pointer也是64位,那么该机器就是LP64的,其中的L表示Long,P表示Pointer,64表示Long和Pointer都是64位的.由于 ...

  8. Java的String&StringBuffer&StringBuilder

    一:String类 1.String对象的初始化 由于String对象特别用,所以在对String对象进行初始化时,Java提供了一种简化的特殊语法,格式如下: String s = "ab ...

  9. Linux系统的命令别名功能

    命令别名功能在管理和维护Linux系统的过程中,将会使用到大量命令,有一些很长的命令或用法经常被用到,重复而频繁地输入某个很长命令或用法是不可取的.这时可以使用命令别名功能将这个过程简单化. 1.系统 ...

  10. python运维开发(十八)----Django(二)

    内容目录 路由系统 模版 Ajax model数据库操作,ORM 路由系统 django中的路由系统和其他语言的框架有所不同,在django中每一个请求的url都要有一条路由映射,这样才能将请求交给对 ...