Concurrency
Thread
线程: 分享 CPU、共享内存(多个线程访问同一数据/对象)
线程一般用于需长时间执行的任务: 循环、下载、浏览图片
Create
创建线程的方法:
- 父类:继承 Thread 类, 重写 run 方法
- 接口:new Thread(Runnable Task)实现 Runnable 接口的类: 实名类/匿名类/Lambda 表达式
Runnable
thread.start() 线程处于可运行状态: 可能在运行, 可能不在运行, 不必始终保持运行
Block
- blocked
- waiting
- timed waiting
Blocked
获取锁不得时, 进入阻塞状态
Waiting
等待调度器时, 进入等待状态
Timed waiting
调用含超时参数的方法时, 进入计时等待状态保持到超时或通知
Object.wait、Thread.sleep、Thread.join、Lock.tryLock、Condition.await
Terminated
run 方法正常退出或抛出未捕获异常时, 进入(自然/意外)死亡状态
优先级
- 默认情况下继承父线程的优先级
- 需防止低优先级线程被饿死(因此不要依赖优先级进行编程)
- MIN_PRIORITY(1)~NORM_PRIORITY(5)~MAX_PRIORITY(10)
- 每当线程调度器选择新线程时,首选具有较高优先级的线程
Daemon
- Thread.setDaemon(true)
- 设置为后台线程: 随时可能中断
- 虚拟机会在只有后台线程时退出,后台线程不可访问固有资源(文件、数据库等)
未捕获异常
实现 Thread.UncaughtExceptionHandler 接口
不安装默认处理器时,默认处理器为空
中断
Interrupt
对一个线程调用此方法时,线程将进入中断状态
Interrupted Exception
对一个阻塞线程(调用 sleep/wait 方法等)调用 interrupt 方法时, 抛出此异常
同步
两个线程都有多个语句, 无法保证一个线程所有语句全部执行完再调用另一个线程,必然会出现交错调用不同线程中的语句现象, 导致调用混乱现象
锁对象 (实例域)
可重复(持有计数), 可共用(共用锁对象的方法可互相调用)
条件对象 (实例域)
管理有锁却不能正常工作的线程
一个锁对象可以有多个相关的条件对象
内部锁
- synchronized 关键字
- 每个对象都有一个内部锁, 可将静态方法声明为 synchronized
- 等价于 wait/notifyAll
- 等价于 await/signalAll
截获内部锁
读写锁
监视器
volatile 关键字:修饰实例域
声明一个域可并发更新,通知编译器和虚拟器注意此特性
死锁
所有线程处于等待或阻塞状态
e.g. 两个线程互相等待状态
Thread Local Helper
线程安全
java.util.concurrent 并发 API: 线程安全(同时只有一个线程调用某对象)
原子整数
AtomicInteger.getAndIncrement(); // cnt++
AtomicInteger.getAndDecrement(); // cnt—
AtomicBoolean
AtomicLong
AtomicReference
集合
- 阻塞队列
- 高效映射表、队列
- 写数组列表和写数组集的拷贝 - CopyOnWriteArrayList 类、CopyOnWriteArraySet 类
- 同步包装器(synchronization wrapper) - 任何集合类通过同步包装器变成线程安全集合类
异步计算
执行器
线程池: 创建大量生命周期短的线程
- CachedThreadPool: 提交任务多, 创建新线程
- FixedThreadPool: 提交任务多, 等待当前任务完成再运行其他任务
- SingleThreadExecutor: 逐一执行提交任务
- ScheduledExecutorService 接口: 预定执行/重复执行任务
以上工厂方法返回: 实现 ExecutorService 接口的 ThreadPoolExecutor 对象
- 创建
ExecutorService pool = Executors.newCachedThreadPool();
- 方法
pool.execute(myTask);
pool.shutdown();
- Future 对象用于查询任务完成情况
Swing
事件分配线程不应进行 input/output/sleep 调用(可能使线程阻塞)
- Timer 类(亦是线程): 每隔一段时间重复执行 MyTask
- 更新图形化界面: SwingUtilities.invokeLater(Runnable MyTask);
EventQueue.invokeLater(new Runnable()
{
public void run()
{
Statements;
}
});
- 指定布局(Layout)
以下可合成一个方法:
- 创建组件(Component)
- 添加组件(getContentPane.add(Component) //得到 Container 类)
- 响应事件(Event)
- 设置属性(size、location、bounds、locationByPlatform、title、iconImage、visible、resizable、undecorated、extendedState)
// 取得点击按钮的名字
String itemName = ((JRadioButton) e.getSource()).getText();
// Source: 事件源(点击按钮事件)