1. Runnable接口
线程类都是实现Runnable接口的run方法
2. Thread类
Thread类也是对Runnable的实现,线程的运行是,将Runnable的实现类交给Thread,Thread通过代理模式,在run方法中调用实现类的代理方法, Thread的start()方法开始线程的执行。
sleep(long millis); sleep(long millis, int nanos) 程序停止运行固定时间
3. ExecutorService
Oracle在JDK1.5后不推荐使用Thread来直接调度线程,而是推荐ExecutorService来进行线程的调度。
将线程任务添加到execute()方法中执行
ExecutorService可以通过Executors的三个方法来获取
1) newCachedThreadPool() 在程序执行过程中创建与所需要相同数量的线程
2) newFixedThreadPool(int ) 一次性预先创建固定个数的线程
3) newSingleThreadPool() 数量为1的FixedThreadPool
4. Callable接口
实现有返回值的线程任务
实现Callable的call方法, 然后交给ExecutorService的submit()方法,会返回Future对象
利用isDone()方法查询任务是否完成,利用get()方法获取结果, 如果任务还没结束,get()方法会阻塞.
5. 进程优先级
JDK有10个优先级,但常用的是三个:
1) Thread.MAX_PRIORITY
2) Thread.NORM_PRIORITY
3) Thread.MIN_PRIORITY
设置优先级Thread.currentThread().setPriority()
获取线程优先级Thread.currentThread().getPriority()
6. Daemon
在thread.start()之间设置 thread.setDeamon(true)
通过isDaemon查询是否是后台线程
7. 加入线程
在线程A中调用B.join(), 那么A将在B执行完后开始执行。
8. 线程的异常捕获
1. 实现Thread.UncaughtExceptionHandler接口的uncaughtException(Thread t, Throwable e)
2. 实现ThreadFactory接口在newThread(Runnable r)方法中 t.setUncaughtExceptionHandler(new handler)
设置默认的ExceptionHandler Thread.setDefaultUncaughtExceptionHandler();
9. 共享资源竞争
1) 关键字synchronized
在使用synchronized的时候,将资源设置为private十分重要,这样才能防止其他任务直接访问
2)Lock对象
private Lock = new ReentrantLock(); lock.lock(); try{ // to the work } finally { lock.unlock(); }
功能相对于关键字synchronized更加强大,但是使用更加复杂
3) volatile
// 待补充
4) 原子类
AtomicInteger AtomicLong AtomicReference
5) 临界区
synchronized(syncObject) { // do the work }
6) 线程本地存储
ThreadLocal<Integer> value = new ThreadLocal<Integer>(){ @Override protected Integer initValue(){ return new Integer(1); } }
利用vlaue.set()和value.get()访问变量
10. 线程状态
1. 新建: 线程被创建时的状态, 完成线程所需资源的分配,有获得CPU时间的资格
2. 就绪: 完成所需资源的分配, 线程可以在运行也可能不在运行,只要分配到时间就运行
3. 阻塞: 因越少必要的资源处于等待状态,不会被调度器分配时间片
4. 死亡: 完成任务,不会再被分配时间片
新建、就绪 --> 阻塞
1) 调用sleep()
2) 调用wait()
3) 等待I/O, 无法被程序中断
4) 等待共享资源, 无法被程序中断
中断线程的方法
1) Thread.interrupt()
2) Executor.shutdownNow()
3) Future.cancel()
强制中断I/O的方法:关闭任务的资源
wait()和sleep()对比
wait | sleep |
Object的方法 | Thread的方法 |
释放锁 | 不释放锁 |
notify() notifyAll()之后恢复执行 | 设定时间之后,恢复执行 |
notify() 只唤醒一个阻塞的任务,notifyAll()将唤醒所有的任务
管道通信
PipedWriter p = new PipedWriter(); p.write(new Object()); PipedReader pr = new PipedReader(p); Object o = (Object) pr.read();
11. 死锁与活锁
死锁: 多个线程之间相互占用部分资源,导致都不能运行。
活锁: 与死锁唯一不同的是,它的状态在不断的变化。 eg: 两个人面对面过桥,他们同时向左右避让,导致无法通过
死锁的四个必要条件
1. 互斥条件. 资源无法共享
2. 持有条件。 持有部分资源,等待其他资源
3. 资源无法被抢占
4. 循环等待