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. HTTP 协议实现

    一.超文本传输协议及HTTP包    HTTP协议用于在Internet上发送和接收消息.HTTP协议是一种请求-应答式的协议--客户端发送一个请求,服务器返回该请求的应答,所有的请求与应答都是HTT ...

  2. webService 客户端接口调用【java】

    最近实际项目中使用到了WebService,简单总结下使用方式: 1.拿到接口:http://*******:8080/osms/services/OrderWebService?wsdl 我们可以将 ...

  3. Windows下PHP开发环境搭建

    PHP集成开发环境有很多,如XAMPP.AppServ......只要一键安装就把PHP环境给搭建好了.但这种安装方式不够灵活,软件的自由组合不方便,同时也不利于学习.所以我还是喜欢手工搭建PHP开发 ...

  4. JConsole 连接配置

    远程监控配置 JDK配置 在%JAVA_HOME%/jre/lib/management目录下,jmxremote.password.template.jmxremote.password需要修改配置 ...

  5. php 依据字符串生成相应数组方法

    php 依据字符串生成相应数组方法 比如: <?php $config = array( 'project|page|index' => 'content', 'project|page| ...

  6. socket原理详解

    1.什么是socket 我们知道进程通信的方法有管道.命名管道.信号.消息队列.共享内存.信号量,这些方法都要求通信的两个进程位于同一个主机.但是如果通信双方不在同一个主机又该如何进行通信呢?在计算机 ...

  7. [转载]启用 VIM 中的 Python 自动补全及提示功能

    转载: http://zhongwei-leg.iteye.com/blog/941474 周围的同事不喜欢使用 VIM 写 Python 代码的原因之一就是,VIM 不能像 Visual Studi ...

  8. 何时可以开启透明数据加密(TDE)?

    TDE可以为我们的数据库提供加密保护,但是,不是任何情况下都可以随意开启TDE的,同时开启TDE后,我们的数据库维护管理工作也需要进行一些调整. 下面我们就先看看开启TDE需要的条件吧! 无法正常开启 ...

  9. Lucene学习总结之一:全文检索的基本原理

    一.总论 根据http://lucene.apache.org/java/docs/index.html 定义: Lucene 是一个高效的,基于Java 的全文检索库. 所以在了解Lucene之前要 ...

  10. java.lang.ClassNotFoundException: org.apache.struts.action.ActionServlet