1.Thread,Runable的关系
2.Thread的生命周期,以及如何管理它。
a) ExecutorService exec = Executors.newCachedThreadPool();
b) ExecutorService exec = Executors.newFixedThreadPool();
c) ExecutorService exec = Executors.newSingleThreadPool();
d) Exec.shutdown()的作用
3.Runnable、Callable的区别(Page658)
4.Thread.yield()
完成run()方法的一次迭代过程后,可以通过yield()方法暗示线程调度器,可以让别的线程使用CPU,但不一定能保证线程调度器会采纳。
5.后台线程(daemom)
所有非后台线程结束后,程序就结束,并会杀死所有的后台线程,假如某个后台线程的run()方法中有finally代码块,如果程序结束,那finally块就不会执行。
6.Thread.join() 方法
7.解决共享资源竞
7.1 使用 synchronized
某一线程处于标记为syschronized的方法中调用时,其他所有要调用类中任何其他被标记为synchronized方法的线程都会被堵塞。因为所有对象都自动含有单一的锁。如果某个线程调用的synchronized方法中又调用了其他的synchronized方法,则加锁次数递增,调用结束加锁次数递减,直到0。
7.2 使用显示的Lock对象
Java SE5的java.util.concurrent.locks类库中有显示的互斥机制。Lock对象必须被显示的创建,锁定,释放。因此它与内建的锁的形式相比,代码缺乏优雅性,但对解决某些类型的问题来说,它更加灵活。比如1:某个事物失败了,那么会抛出异常,用显示的Lock对象,就可以在finally子句中将系统维护在正确的状态中。比如2:ReentrantLock允许你尝试获取但最终未获取锁,这样如果其他人已经获取了这个锁,那你就可以决定离开去执行一些其他的事情,而不是一直等待这个锁释放。
7.3线程本地存储
ThreadLocal对象通常当作静态域存储,它可以为使用相同变量的每个不同的线程都创建不同的存储,比如你有5个线程都要用变量x所表示的对象,那ThreadLoacl就会生成5个用于x的不同的存储块。
8.原子性与易变性
原子性可以应用于除long和double之外的所有基本类型之上的“简单操作”。long和double是64位的,JVM会将64位的读取和写入当作两个分离的32位操作来执行。要保证long和double变量的原子性,可以使用volatile关键字。volatile关键字确保了应用中的可视性。volatile域会立即被写入到主存中,而读取操作就发生在主存中。原子性的读取操作会在中间使用缓存,这不能使一个变量的操作的可视性得到保证。如果一个域定义为volatile,那么它就会告诉编译器不要执行任何移除读取和写入的优化操作。
8.1原子类
Java SE5引入了诸如AtomicInteger,AtomicLong,AtomicReference等特殊的原子性变量类。
8.2临界区
只希望防止多个线程同时访问方法内部的部分代码而不是防止访问整个方法,可以使用同步控制块。 Synchronized(syncObject) { //... }这个区域也叫临界区。使用同步控制块,可以使多个任务访问对象的时间性能得到显著的提高。
9.线程的中断
http://www.jb51.net/article/32359.htm
10.线程之间的协作wait() notify() notifyAll()
只能在同步控制方法或同步控制块里面调用这些方法,因为这些方法的调用前提是必须拥有对象的锁,如果在非同步控制方法里面调用,则会抛异常,如:当前线程不是拥有者。
notifyAll()因某个特定锁而被调用时,只有等待这个锁的任务才会被唤醒。
11.生产者与消费者
12.免锁容器
像Vector和Hashtable这类早期容器具有许多synchronized方法,当它们用于非多线程的程序中时,便会导致不可接受的开销。Java SE5通过更灵巧的技术来消除加锁,从而提高线程的安全性。这些免锁容器背后的策略:(Page 755)