第一章 线程管理
Thread保存的一些属性:
ID
name
priority(1
~ 10)
status(new,
runnable, blocked, waiting, time waiting,
terminated)
中断相关:
interrupt可以停止线程,但不是预期的结果;
interruptisInterrupted(),
interrupted()用来判断线程是否中断,前者不能改变interrupted属性的值,后者能设其为false。
join的用法:
线程1中调用线程2的join,需要等线程2执行完成,线程1才能完成。
thread2.join(1000):线程2执行完成或者1000ms之后,thread1解除挂起。
常驻进程:
setDaemon()方法只能在start()方法被调用之前设置。一旦线程开始运行,将不能再修改守护状态。
线程局部变量:P27例子
ThreadLocal startDate =
newThreadLocal();解决线程共享问题。
线程分组:
ThreadGroup
group =
newThreadGroup(“search”);创建线程组
Thread test
= new Thread(group, runnable);创建线程到线程组
threadGroup.activeCount()获取线程组中包含的线程数目。
threadGroup.enumerate()获取线程组包含的线程列表。
threadGroup.interrupt()中断线程组中的线程。
第二章 线程同步基础
使用synchronized、wait和notify实现生产者消费者同步
synchronized关键字用来同步对象、方法或者代码块
wait()线程挂起
notify()和notifyAll()唤醒挂起的线程
使用Lock锁实现生产者消费者同步
synchronized只能在同一个快结构中获取和释放控制,Lock允许实现更比synchronized复杂的临界区结构。Lock接口拥有更好的性能。
Lock的用法
private final Lock queueLock =
new ReentrantLock();
queueLock.lock();
待控制同步代码模块
queueLock.unlock();
读写锁
锁机制最大的改进之一就是ReadWriteLock接口和它的唯一实现类ReentrantReadWriteLock。这个类有两个锁,一个是读操作锁,另一个是写操作锁。使用读操作锁时可以允许多个线程同时访问,但是不可进行修改操作;而使用写操作锁时只允许一个线程进行。在一个线程执行写操作时,其他线程不能够执行读操作。
锁的公平性
ReentrantReadWriteLock(Boolean
isFair)构造函数有个布尔型入参表示是否公平,true公平,从等待的线程里面选择一个等待最长的运行。false非公平,则下个从等待的线程里面随机选择一个执行。
在锁中使用多条件
ReentrantLocklock
= newReentrantLock();
Condition
lines = lock.newCondition();
Condition
space= lock.newCondition();
lock.lock();
// 生产者模块
lines.await();
space.signalAll();
// 消费者模块
space.await();
lines.signalAll();
lock.unlock();
第五章
Fork/Join框架
1、创建Fork / Join线程池
ForkJoinPool 的用法:
ForkJoinPool pool = new ForkJoinPool();
pool.execute(task);
do{
......
}while(!task.isDone)
pool.shutdown();
public class Task extends RecursiveAction{
......
}
compute方法,实现任务的执行逻辑。
2、合并任务的结果 P179
RecursiveTask的用法:
public class DocumentTask extends
RecursiveTask{
...
}
RecursiveTask task = new RecursiveTask(......);
task 的compute中执行分治:
RecursiveTask task1 = new
RecursiveTask(......);
RecursiveTask task2 = new
RecursiveTask(......);
invokeAll(task1, task2);
result = grouResults(task1.get(), task2.get());
return result;
pool.execute(task);
...
pool.shutdown();
pool.awaitTermination(1, TimeUnit.DAYS);
print(task.get());
3、异步运行任务
3.1 运行任务:
采用同步方式,例如使用invokeAll()方法时,发送任务给Fork/Join线程池的方法直到任务执行完成后才返回结果。
相反,当采用异步方法(比如fork)时,任务将继续执行,因此ForkJoinPool类无法使用工作窃取算法来提升应用程序的性能。只有调用join()、get()方法来等待任务的结束时,ForkJoinPool类才可以使用工作窃取算法; join()方法在主任务中被调用,然后等待任务执行结束,并通过comute()方法返回值。
3.2 取消任务
task.cancel(isTrue)
cancel方法允许取消一个仍没有执行的任务,这是非常重要的。如果任务已经开始执行,那么调用cancel()方法也无法取消。
如果传递true,即使任务正在执行也将被取消。
遗留问题:
RecursiveAction
和RecursiveTask的区别?
Re:
RecursiveAction用于任务没有返回结果的场景。
RecursiveTask用于任务有返回结果的场景。
我们的目标是边开发变成长,早日成为一名卓越的工程师,而不仅仅只是像劳役一样地不停地为完成任务和做任务。