学习hadoop,nio和线程用的很多,基础从这里找吧
从csdn下的
http://dl.iteye.com/upload/picture/pic/84809/2e8a1e5f-2c36-3cfa-8c3c-acb471e607f3.jpg
关于util.concurrent,查看
http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html
关于concurrentMap,参考
http://blog.csdn.net/waitforcher/archive/2009/05/24/4211896.aspx
把jpg扩展名改成zip,解压后是ibm的线程的教程
单个变量的准确性用volatile,多变量(类似事务)用synchronized
Collections 类提供了一组便利的用于 List、Map 和 Set 接口的封装器,可以用 Collections.synchronizedMap 封装 Map,它将确保所有对该映射的访问都被正确同步。
jdk1.6有个concurrentMap
-------------------------------
概念:
---------------------------------
同步可以让我们确保线程看到一致的内存视图。
处理器可以使用高速缓存加速对内存的访问(或者编译器可以将值存储到寄存器中以便进行更快的访问)。在一些多处理器体系结构上,如果在一个处理器的高速缓存中修改了内存位置,没有必要让其它处理器看到这一修改,直到刷新了写入器的高速缓存并且使读取器的高速缓存无效。
这表示在这样的系统上,对于同一变量,在两个不同处理器上执行的两个线程可能会看到两个不同的值!这听起来很吓人,但它却很常见。它只是表示在访问其它线程使用或修改的数据时,必须遵循某些规则。
Volatile 比同步更简单,只适合于控制对基本变量(整数、布尔变量等)的单个实例的访问。当一个变量被声明成 volatile,任何对该变量的写操作都会绕过高速缓存,直接写入主内存,而任何对该变量的读取也都绕过高速缓存,直接取自主内存。这表示所有线程在任何时候看到的 volatile 变量值都相同。
如果没有正确的同步,线程可能会看到旧的变量值,或者引起其它形式的数据损坏
---------------------------------------------------
例子:
----------------------------------------------------
//在一定时间内计算素数:注意volatile 的使用
public class CalculatePrimes extends Thread {
public static final int MAX_PRIMES = 1000000;
public static final int TEN_SECONDS = 1000;
public volatile boolean finished = false;
public void run() {
int[] primes = new int[MAX_PRIMES];
int count = 0;
for (int i=2; count<MAX_PRIMES; i++) {
// Check to see if the timer has expired
if (finished) {
break;
}
boolean prime = true;
for (int j=0; j<count; j++) {
if (i % primes[j] == 0) {
prime = false;
break;
}
}
if (prime) {
primes[count++] = i;
System.out.println("Found prime: " + i);
}
}
}
public static void main(String[] args) {
CalculatePrimes calculator = new CalculatePrimes();
calculator.start();
try {
Thread.sleep(TEN_SECONDS);
}
catch (InterruptedException e) {
// fall through
}
calculator.finished = true;
}
}
//定时结束标识
import java.util.Timer;
import java.util.TimerTask;
public class CalculatePrimesTest {
public static void main(String[] args) {
Timer timer = new Timer();
final CalculatePrimes calculator = new CalculatePrimes();
calculator.start();
timer.schedule(new TimerTask() {
public void run() {
calculator.finished = true;
}
}, CalculatePrimes.TEN_SECONDS);
}
}
//多线程得到大数组的最大值
public class TenThreads {
private static class WorkerThread extends Thread {
int max = Integer.MIN_VALUE;
int[] ourArray;
public WorkerThread(int[] ourArray) {
this.ourArray = ourArray;
}
// Find the maximum value in our particular piece of the array
public void run() {
for (int i = 0; i < ourArray.length; i++)
max = Math.max(max, ourArray[i]);
}
public int getMax() {
return max;
}
}
public static void main(String[] args) {
WorkerThread[] threads = new WorkerThread[10];
int[][] bigMatrix = {{12,3,42,3,4},{12,3,42,3,4},{12,3,42,3,4},{12,3,42,3,4},{12,3,42,3,4},{12,3,42,3,4},{12,3,42,3,4},{12,3,42,3,4},{12,3,42,3,4},{12,3,42,3,4}};//getBigHairyMatrix();
int max = Integer.MIN_VALUE;
// Give each thread a slice of the matrix to work with
for (int i=0; i < 10; i++) {
threads[i] = new WorkerThread(bigMatrix[i]);
threads[i].start();
}
// Wait for each thread to finish
try {
for (int i=0; i < 10; i++) {
threads[i].join();
max = Math.max(max, threads[i].getMax());
}
}
catch (InterruptedException e) {
// fall through
}
System.out.println("Maximum value was " + max);
}
}
使用synchronized 的例子:
使用 synchronized 块可以让您将一组相关更新作为一个集合来执行,而不必担心其它线程中断或看到计算的中间结果。以下示例代码将打印“1 0”或“0 1”。如果没有同步,它还会打印“1 1”
haoning:这里锁了一个对象,所以在两个对象里同时调用第三个对象的锁,保证是一个锁,下面另一个例子不是一个锁所以互不影响
public class SyncExample {
private static Object lockObject = new Object();
private static int x, y;
private static class Thread1 extends Thread {
public void run() {
synchronized (lockObject) {
x = y = 0;
System.out.println(x);
}
}
}
private static class Thread2 extends Thread {
public void run() {
synchronized (lockObject) {
x = y = 1;
System.out.println(y);
}
}
}
public static void main(String[] args) {
new Thread1().run();
new Thread2().run();
}
}
Java 锁定合并了一种互斥形式。每次只有一个线程可以持有锁。锁用于保护代码块或整个方法,必须记住是锁的身份保护了代码块,而不是代码块本身,这一点很重要。一个锁可以保护许多代码块或方法。
反之,仅仅因为代码块由锁保护并不表示两个线程不能同时执行该代码块。它只表示如果两个线程正在等待相同的锁,则它们不能同时执行该代码。
在以下示例中,两个线程可以同时不受限制地执行 setLastAccess() 中的 synchronized 块,因为每个线程有一个不同的 thingie 值。因此,synchronized 代码块受到两个正在执行的线程中不同锁的保护。
import java.util.Date;
public class SyncExampleTest {
public static class Thingie {
private Date lastAccess;
public synchronized void setLastAccess(Date date) {
this.lastAccess = date;
System.out.println(this.lastAccess);
}
}
public static class MyThread extends Thread {
private Thingie thingie;
public MyThread(Thingie thingie) {
this.thingie = thingie;
}
public void run() {
thingie.setLastAccess(new Date());
}
}
public static void main(String args[]) {
Thingie thingie1 = new Thingie(), thingie2 = new Thingie();
new MyThread(thingie1).start();
new MyThread(thingie2).start();
}
}
SimpleCache.java 使用 HashMap 为对象装入器提供了一个简单的高速缓存。load() 方法知道怎样按对象的键装入对象。在一次装入对象之后,该对象就被存储到高速缓存中,这样以后的访问就会从高速缓存中检索它,而不是每次都全部地装入它。对共享高速缓存的每个访问都受到 synchronized 块保护。由于它被正确同步,所以多个线程可以同时调用 getObject 和 clearCache 方法,而没有数据损坏的风险
import java.util.HashMap;
import java.util.Map;
public class SimpleCache {
private final Map cache = new HashMap();
public Object load(String objectName) {
// load the object somehow
return objectName;
}
public void clearCache() {
synchronized (cache) {
cache.clear();
}
}
public Object getObject(String objectName) {
Object o;
synchronized (cache) {
o = cache.get(objectName);
if (o == null) {
o = load(objectName);
cache.put(objectName, o);
}
}
return o;
}
}
用于一致性的同步:
/*如果多个线程试图同时使用这个类,会发生什么?这可能是个灾难。因为没有同步,多个线程可以同时执行 push() 和 pop()。如果一个线程调用 push(),而另一个线程正好在递增了 top 并要把它用作 values 的下标之间调用 push(),会发生什么?结果,这两个线程会把它们的新值存储到相同的位置!当多个线程依赖于数据值之间的已知关系,但没有确保只有一个线程可以在给定时间操作那些值时,可能会发生许多形式的数据损坏,而这只是其中之一。
对于这种情况,补救办法很简单:同步 push() 和 pop() 这两者,您将防止线程执行相互干扰。
请注意,使用 volatile 还不够 — 需要使用 synchronized 来确保 top 和 values 之间的关系保持一致。
*/
public class UnsafeStack {
public int top = 0;
public int[] values = new int[1000];
public void push(int n) {
values[top++] = n;
}
public int pop() {
return values[--top];
}
}
/* 当我们要递增计数器时,会发生什么?请看 increment() 的代码。它很清楚,但不是线程安全的。如果两个线程试图同时执行 increment(),会发生什么?计数器也许会增加 1,也许增加 2。令人惊奇的是,把 counter 标记成 volatile 没有帮助,使 get() 和 set() 都变成 synchronized 也没有帮助。
设想计数器是零,而两个线程同时执行递增操作代码。这两个线程会调用 Counter.get(),并且看到计数器是零。现在两个线程都对它加一,然后调用 Counter.set()。如果我们的计时不太凑巧,那么这两个线程都看不到对方的更新,即使 counter 是 volatile,或者 get() 和 set() 是 synchronized。现在,即使计数器递增了两次,得到的值也许只是一,而不是二。
要使递增操作正确运行,不仅 get() 和 set() 必须是 synchronized,而且 increment() 也必需是 synchronized!否则,调用 increment() 的线程可能会中断另一个调用 increment() 的线程。如果您不走运,最终结果将会是计数器只增加了一次,不是两次。同步 increment() 防止了这种情况的发生,因为整个递增操作是原子的。
当循环遍历 Vector 的元素时,同样如此。即使同步了 Vector 的方法,但在循环遍历时,Vector 的内容仍然会更改。如果要确保 Vector 的内容在循环遍历时不更改,必须同步整个代码块
*/
public class Counter {
private int counter = 0;
public int get() {
return counter;
}
public void set(int n) {
counter = n;
}
public void increment() {
set(get() + 1);
}
}
---------------------------
死锁
/*
如果有一组进程或线程,其中每个都在等待一个只有其它进程或线程才可以执行的操作,那么就称它们被死锁了。
最常见的死锁形式是当线程 1 持有对象 A 上的锁,而且正在等待与 B 上的锁,而线程 2 持有对象 B 上的锁,却正在等待对象 A 上的锁。这两个线程永远都不会获得第二个锁,或者释放第一个锁。它们只会永远等待下去。
要避免死锁,应该确保在获取多个锁时,在所有的线程中都以相同的顺序获取锁。
同步准则:当编写 synchronized 块时,有几个简单的准则可以遵循,这些准则在避免死锁和性能危险的风险方面大有帮助:
使代码块保持简短。Synchronized 块应该简短 — 在保证相关数据操作的完整性的同时,尽量简短。把不随线程变化的预处理和后处理移出 synchronized 块。
不要阻塞。不要在 synchronized 块或方法中调用可能引起阻塞的方法,如 InputStream.read()。
在持有锁的时候,不要对其它对象调用方法。这听起来可能有些极端,但它消除了最常见的死锁源头。
*/