java多线程
1.信号量
信号量,有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。
信号量对可用许可进行计数,并采取相应的行动。拿到信号量许可的线程可以进入代码,否则就等待。通过申请和释放方法获取和释放访问许可。
信号量的工作机制就类似于车位计数器,当车位不足时才出来干预,等有车从车库出来,才允许下一辆车进去。
2.线程池
为了防止资源不足,服务器应用程序需要采取一些办法来限制任何给定时刻处理的请求数目,尽可能减少创建和销毁线程的次数,尽量利用已有对象来进行服务。
线程池主要用来解决线程生命周期开销问题和资源不足问题。通过对多个任务重复使用线程,线程创建的开销就被分摊到了多个任务上了,而且由于在请求到达时线程已经存在,所以消除了线程创建所带来的延迟。
一个简单的线程池至少包括了:线程池管理器、工作线程、任务队列、任务接口
线程池管理器
创建、销毁并管理线程池,将工作线程放入线程池中
工作线程
一个可以循环执行任务的线程,在没有任务是进行等待
任务列队
提供一种缓冲机制,将没有处理的任务放在任务列队中
任务接口
每个任务必须实现的接口,主要用来规定任务的入口、任务执行完后的收尾工作、任务的执行状态等,工作线程通过该接口调度任务的执行
示例代码:
执行线程:
在上述代码中 ,当flag为 true 时,证明执行线程想处理某一任务,则通过调用 this.notify()唤醒线程,当任务处理结束后,通过setRunning(false)和调用 this.wait()阻塞本线程。
调度器:
在调度器中先声明一个池容器作为属性,在通过判断currentThread.runningFlag 的状态来判断线程是否空闲去执行任务。
生产者-消费者模式
1.生产者消费者模式准确说应该是“生产者-消费者-仓储”模式
如图所示:
生产者 —> (缓存仓库) <— 消费者
2.生产者仅仅在仓储未满时候生产,仓满则停止生产
3.消费者仅仅在仓储有产品时候才能消费,仓空则等待
4.当消费者发现仓储没产品可消费时候会通知生产者生产
5.生产者在生产出可消费产品时候,应该通知等待的消费者去消费
ThreadLocal
1.ThreadLocal用来解决多线程程序的并发问题
2.ThreadLocal并不是一个Thread,而是Thread的局部变量,当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
简单的说,ThreadLocal 只是一个局部变量,可以在多个线程中共享使用,在一个线程中改变了它的值,也不影响在其他线程中的值。
原子操作类
原子操作类相当于泛化的volatile变量,能够支持原子读取-修改-写操作。
简单来说,原子操作类就是把竞争的内容精确到单个元素,然后对元素进行操作。
Lock锁接口及重入锁
锁接口
Runnable与Callable两个接口的区别在于:
Runnable提供的任务方法为run,它不能返回任何的结果
Callable接口提供的任务方法为call,它可以返回任务执行后的结果
重入锁:ReentrantLock
1.可重入的独占锁。该对象与synchronized关键字有着相同的表现和更清晰的语义,能够清晰地指出哪里上了锁,哪里释放了锁。
2.可重入锁被最近的一个成功lock的线程占有(unlock后释放)。该类有一个重要特性体现在构造器上,构造器接受一个可选参数,是否是公平锁,默认是非公平锁
公平锁:
先来一定先排队,一定先获取锁
非公平锁:
不保证上述条件。非公平锁的吞吐量更高