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. Unity SendMessage方法

    我们今天研究下SendMessage方法, 如果我们需要执行某一个组件的方法时候可以使用SendMessage gameObject.SendMessage("A"); 即可通知当 ...

  2. PLSql连接远程Oracle方法

  3. DM6437 dsp系列之启动过程全析(2)—AIS文件解析

    本文均属自己阅读源码的点滴总结,转账请注明出处谢谢. 欢迎和大家交流.qq:1037701636 email: gzzaigcn2009@163.com,gzzaigcn2012@gmail.com ...

  4. 使用INTERVAL YEAR TO MONTH类型

    Oracle Database 9i数据库引入了一种新特性,可以用来存储时间间隔.时间间隔的例子包括: ● 1年零3个月 ● 25个月 ● -3天5小时16分 ● 1天7小时 ● -56小时 注意: ...

  5. .NET基础拾遗(1)类型语法基础和内存管理基础2

    二.内存管理和垃圾回收 2.1 .NET中栈和堆 每一个.NET应用程序最终都会运行在一个OS进程中,假设这个OS的传统的32位系统,那么每个.NET应用程序都可以拥有一个4GB的虚拟内存..NET会 ...

  6. 关于android的SQLiteDatabase和Cursor的一些疑问

    android数据库操作的基础有三个类:SQLiteOpenHelper,SQLiteDatabase和Cursor.其中,SQLiteOpenHelper会建立一个数据库连接,它虽然可以调用多次ge ...

  7. Asp.net文件缓存依赖

    Asp.net文件缓存依赖 using System; using System.Collections.Generic; using System.Linq; using System.Web; u ...

  8. C#获取QQ旋风的下载记录

    /* * 用户:从前的我 * 日期:2015/8/26 */ using System; using System.IO; namespace GetXf { class Program { publ ...

  9. 关于Ajax技术中servlet末尾的输出流

    Ajax的服务器端用PrintWriter out=resp.getWriter()来响应数据的时候,out.print(0).out.print(1)来表示成功或失败,而不用out.write是有原 ...

  10. C++服务器设计(六):设备连接的生命周期管理

    生命周期介绍 每一个服务器系统的新连接从建立开始时,均会经历多个阶段.比如连接的建立,登录的验证,退出前的资源释放等.同时在具体的消息处理中,还会遇到不可识别的消息事件,或者消息处理时出现数据错误等. ...