为什么使用多线程
- 进程之间不能共享内存,但线程之间共享内存很容易
- 系统创建进程需要为该进程重新分配系统资源,但创建线程代价小得多,因此使用多线程来实现多任务并发比多进程的效率高
- JAVA内置了多线程功能支持,而不是单纯的作为底层操作系统的调度方式,从而简化了JAVA的多线程编程
线程的创建
- 继承
Thread
类(可直接使用this
关键字获得当前对象,多个线程无法共享线程类的实例变量) - 实现
Runnable
接口(必须使用Thread.currentThread()
方法,多个线程可以共享线程类的实例变量) - 使用
Callable
和Future
创建线程(call()
方法作为线程执行体,可以有返回值去,可以声明抛出异常)
线程的生命周期
- 新建(New)--使用
new
关键词新建一个线程 - 就绪(Runnable)--调用
start()
方法 - 运行(Running)--处于就绪状态的线程获得CPU,开始执行
run()
方法体 - 阻塞(Blocked)
线程调用sleep()
方法主动放弃所占用的处理器资源
线程调用了一个阻塞式的IO方法
线程试图获得一个同步监视器,但该监视器被其他线程所持有
线程在等待某个通知
程序调用了线程的suspend()
方法将该线程挂起(容易导致死锁) - 死亡(Dead)
run()
方法或call()
方法执行完成,线程正常结束
线程抛出一个未捕获的异常
直接调用该线程的stop()
方法来结束该线程(容易导致死锁)
控制线程
join()
方法--当某个程序执行流中调用其他程序的join()
方法时,调用线程被阻塞,直到join()
方法加入的join线程执行完为止setDemon()
方法--将指定线程设置为守护线程sleep()
方法--暂停线程的执行,并进入阻塞状态yield()
方法--暂停线程的执行,并进入就绪状态setPriority()
方法--改变线程的优先级,让优先级高的线程获得更多的执行机会
线程同步
- 同步代码块(同步监视器为
obj
)synchronized(obj){ ... }
- 同步方法(同步监视器为
this
)public synchronized void draw{ }
同步锁(Lock)
//定义锁对象 private final ReentrantLock lock = new ReentrantLock(); //加锁 lock.lock(); //释放锁 lock.unlock();
- 释放同步监视器的锁定
- 当前线程的同步方法,同步代码块执行结束
- 当前线程在同步方法,同步代码块遇到
break
,return
终止了继续执行 - 当前线程在同步方法,同步代码块出现未处理的异常
- 当前线程执行同步方法,同步代码块时执行了同步监视器对象的
wait()
方法
- 不释放同步监视器的情况
- 线程执行同步方法,同步代码块时,程序调用
Thread.sleep()
,Thread.yield()
方法来暂停当前线程的执行 - 线程执行同步代码块时,其他线程调用了该线程的
suspend()
方法将该线程挂起
线程通信
- 传统的线程通信
对于使用synchronized
修饰的同步方法或代码块,借助Object
类提供的wait()
,notify()
,notifyAll()
方法 - 使用Condition控制线程通信
如果程序显式使用Lock
对象保证同步,则使用Condition
对象的await()
,signal()
,signalAll()
来控制程序的协调运行 - 使用阻塞队列(BlockingQueue)控制线程通信
BlockingQueue
接口:put()
方法尝试把元素放入队列中,入托队列元素已满,则阻塞该线程,take()
方法尝试从队列头部去取出元素,如果队列元素已空,则阻塞该线程
线程池
Executors
工厂类来产生线程池//返回ExecutorService对象的方法 newCachedThreadPool() newFixedThreadPool(int nThreads) newSingleThreadExecutor() //返回ScheduleExecutorService线程池的方法 newScheduledThreadPool(int corePoolSize) newSingleThreadScheduledExecutor() //生成work stealing池,相当于后台线程池 ExecutorService newWorkStealingPool(int parallelism) ExecutorService newWorkStealingPool()
- 创建
Runnable
或者Callable
实现类的实例 - 调用
ExecutorService
对象的submit()
方法来提交Runnable
或者Callable
实例 调用
ExecutorService
对象的shutdown()
方法关闭线程池
ForkJoinPool
--充分利用多核CPU
- 创建
ForkJoinPool
实例 - 创建有继承了返回值的
RecursiveTask
或无返回值的RecursiveAction
实例 调用
ForkJoinPool
的submit(ForkJoinTask task)
或submit(ForkJoinAction action)
方法来执行指定任务线程相关类
ThreadLocal
类
隔离多个线程的数据共享,从根本上避免多个线程之间对共享资源的竞争- 包装线程不安全的集合类
使用Collections
提供的类方法包装 - 线程安全的集合类
- 以
Concurrent
开头的集合类 - 以
CopyOnWrite
开头的集合类