jucccccccccccccc

  • 两者最主要的区别在于:sleep() 方法没有释放锁,而 wait() 方法释放了锁
  • 两者都可以暂停线程的执行。
  • wait() 通常被用于线程间交互/通信,sleep()通常被用于暂停执行。
  • wait() 方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的 notify()或者 notifyAll() 方法。sleep()方法执行完成后,线程会自动苏醒。或者可以使用 wait(long timeout) 超时后线程会自动苏醒。

 调用 start() 方法方可启动线程并使线程进入就绪状态,直接执行 run() 方法的话不会以多线程的方式执行。

synchronized(xxx.class)会锁住所有该类

synchronized 和 ReentrantLock都是可重入锁

synchronized 依赖于 JVM

方法级的同步通过常量池中的方法表结构中的 ACC_SYNCHRONIZED 访问标志

代码块的同步是利用monitorenter和monitorexit这两个字节码指令

而 ReentrantLock 依赖于 API

reentrantlock:等待可中断,可实现公平锁

synchronized只能是非公平锁

wait()使当前线程阻塞,前提是 必须先获得锁,一般配合synchronized 关键字使用,即,一般在synchronized 同步代码块里使用 wait()、notify/notifyAll() 方法

当线程执行wait()方法时候,会释放当前的锁,然后让出CPU,进入等待状态。

让线程按顺序执行

  • [1] 使用线程的join方法
  • [2] 使用主线程的join方法
  • [3] 使用线程的wait方法
  • [4] 使用线程的线程池方法
  • [5] 使用线程的Condition(条件变量)方法
  • [6] 使用线程的CountDownLatch(倒计数)方法
  • [7] 使用线程的CyclicBarrier(回环栅栏)方法
  • [8] 使用线程的Semaphore(信号量)方法

中断一个线程

interrupt 方法,可以通过 isInterrupted()来判断是否被中断

通过 interrupt,设置了一个标识告诉线程可以终止了,线程中还提供了静态方法 Thread.interrupted()对设置中断标识的线程复位

定义一个volatile 修饰的成员变量boolean,来控制线程的终止,while循环判断变量boolean是否需要结束while。

threadlocal

每个线程都会有这个变量的本地副本

Thread 类中有一个 threadLocals 和 一个 inheritableThreadLocals 变量

都是 ThreadLocalMap 类型的变量,我们可以把 ThreadLocalMap 理解为ThreadLocal 类实现的定制化的 HashMap。默认情况下这两个变量都是 null,只有当前线程调用 ThreadLocal 类的 setget方法时才创建它们,实际上调用这两个方法的时候,我们调用的是ThreadLocalMap类对应的 get()set()方法

最终的变量是放在了当前线程的 ThreadLocalMap 中

ThreadLocalMap可以存储以ThreadLocal为 key ,Object 对象为 value 的键值对

ThreadLocalMap 中使用的 key 为 ThreadLocal 的弱引用,而 value 是强引用。所以,如果 ThreadLocal 没有被外部强引用的情况下,在垃圾回收的时候,key 会被清理掉,而 value 不会被清理掉。这样一来,ThreadLocalMap 中就会出现 key 为 null 的 Entry。假如我们不做任何措施的话,value 永远无法被 GC 回收,这个时候就可能会产生内存泄露。ThreadLocalMap 实现中已经考虑了这种情况,在调用 set()get()remove() 方法的时候,会清理掉 key 为 null 的记录

CopyOnWriteArrayList 类的所有可变操作(add,set 等等)都是通过创建底层数组的新副本来实现的。当 List 需要被修改的时候,我并不修改原有内容,而是对原有数据进行一次复制,将修改的内容写入副本。写完之后,再将修改完的副本替换原来的数据,这样就可以保证写操作不会影响读操作了 

ReentrantReadWriteLock,它表示两个锁,一个是读操作相关的锁,称为共享锁;一个是写相关的锁,称为排他锁,描述如下:

线程进入读锁的前提条件:

没有其他线程的写锁,

没有写请求或者有写请求,但调用线程和持有锁的线程是同一个。

线程进入写锁的前提条件:

没有其他线程的读锁

没有其他线程的写锁

synchronized 同步语句块的实现使用的是 monitorenter 和 monitorexit 指令
当执行 monitorenter 指令时,线程试图获取锁也就是获取 对象监视器 monitor 的持有权
在执行 monitorexit 指令后,将锁计数器设为 0,表明锁被释放。如果获取对象锁失败,那当前线程就要阻塞等待,直到锁被另外一个线程释放为止。
 synchronized 和 ReentrantLock 的区别
都是可重入锁
synchronized 依赖于 JVM 而 ReentrantLock 依赖于 API
volatile 关键字能保证数据的可见性,但不能保证数据的原子性。synchronized 关键字两者都能保证。
ThreadLocal类主要解决的就是让每个线程绑定自己的值,可以将ThreadLocal类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。

Thread 类中有一个 threadLocals 和 一个 inheritableThreadLocals 变量,它们都是 ThreadLocalMap 类型的变量,
我们可以把 ThreadLocalMap 理解为ThreadLocal 类实现的定制化的 HashMap。默认情况下这两个变量都是 null,
只有当前线程调用 ThreadLocal 类的 set或get方法时才创建它们,实际上调用这两个方法的时候,
我们调用的是ThreadLocalMap类对应的 get()、set()方法。
最终的变量是放在了当前线程的 ThreadLocalMap 中,并不是存在 ThreadLocal 上
ThreadLocalMap可以存储以ThreadLocal为 key ,Object 对象为 value 的键值对        全局存储用户信息 

AQS 为构建锁和同步器提供了一些通用功能的是实现  ReentrantLock,Semaphore,其他的诸如 ReentrantReadWriteLock

stampedLock优化读写锁,读锁用乐观锁,避免写锁可能的饿死情况。
如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。
如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,
这个机制 AQS 是用 CLH 队列锁实现的,即将暂时获取不到锁的线程加入到队列中。
在 tryAcquire 方法中,如果发现锁这个时候被释放了(state == 0),非公平锁会直接 CAS 抢锁,但是公平锁会判断等待队列是否有线程处于等待状态,如果有则不去抢锁,乖乖排到后面

Semaphore(信号量)可以指定多个线程同时访问某个资源  STATE -- PERMITS
CountDownLatch 允许 count 个线程阻塞在一个地方,直至所有线程的任务都执行完毕。
构造 AQS 的 state 值为 count。当线程使用 countDown() 方法时,其实使用了tryReleaseShared方法以 CAS 的操作来减少 state,直至 state 为 0 
当调用 await() 方法的时候,如果 state 不为 0,那就证明任务还没有执行完毕,await() 方法就会一直阻塞,也就是说 await() 方法之后的语句不会被执行。
然后,CountDownLatch 会自旋 CAS 判断 state == 0,如果 state == 0 的话,就会释放所有等待的线程,await() 方法之后的语句得到执行。

CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,
直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。
CountDownLatch 是计数器,只能使用一次,而 CyclicBarrier 的计数器提供 reset 功能,可以多次使用

JAVA的并发包提供了读写锁ReentrantReadWriteLock,它表示两个锁,一个是读操作相关的锁,称为共享锁;一个是写相关的锁,称为排他锁,描述如下:
线程进入读锁的前提条件,没有其他线程的写锁,,没有写请求或者有写请求,但调用线程和持有锁的线程是同一个。,线程进入写锁的前提条件:,没有其他线程的读锁,没有其他线程的写锁

生产者消费者模式,通过阻塞队列workqueue将任务和线程解耦

首先检测线程池运行状态,如果不是RUNNING,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
如果workerCount < corePoolSize,则创建并启动一个线程来执行新提交的任务。
如果workerCount >= corePoolSize,且线程池内的阻塞队列未满,则将任务添加到该阻塞队列中。
如果workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满,则创建并启动一个线程来执行新提交的任务。
如果workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。

任务申请:一种是任务直接由新创建的线程执行。另一种是线程从任务队列中获取任务然后执行,执行完任务的空闲线程会再次去从队列中申请任务再去执行。
第一种情况仅出现在线程初始创建的时候,第二种是线程获取任务绝大多数的情况

快速响应用户请求
获取最大的响应速度去满足用户,所以应该不设置队列去缓冲并发任务,调高corePoolSize和maxPoolSize去尽可能创造多的线程快速执行任务
快速处理批量任务
如何使用有限的资源,尽可能在单位时间内处理更多的任务,也就是吞吐量优先的问题。所以应该设置队列去缓冲并发任务,
调整合适的corePoolSize去设置处理任务的线程数。在这里,设置的线程数过多可能还会引发线程上下文切换频繁的问题,
也会降低处理任务的速度,降低吞吐量。

JDK允许线程池使用方通过ThreadPoolExecutor的实例来动态设置线程池的核心策略,以setCorePoolSize为方法例,
在运行期线程池使用方调用此方法设置corePoolSize之后,线程池会直接覆盖原来的corePoolSize值,
并且基于当前值和原始值的比较结果采取不同的处理策略。对于当前值小于当前工作线程数的情况,说明有多余的worker线程,
此时会向当前idle的worker线程发起中断请求以实现回收,多余的worker在下次idel的时候也会被回收;
对于当前值大于原始值且当前队列中有待执行任务,则线程池会创建新的worker线程来执行队列任务

keepAliveTime  unit   threadFactory  handler

开始--提交任务--线程池是否运行-是-线程数小于核心数-否-阻塞队列已满-是-----------------线程数小于最大线程数-是-增加工作线程并执行
                          任务拒绝                 添加工作线程并执行   添加到阻塞队列等待工作线程执行    任务拒绝。   

CPU 密集型的,可以把核心线程数设置为核心数+1                                                                FixedThreadPool 的 core和 ma 都被设置为 n  无界队列 LinkedBlockingQueue在任务比较多的时候会导致 OOM
IO  2*CPU 核心数  25*CPU 核心数                        CachedThreadPool 的core 被设置为空max被设置为 Integer.MAX.VALUE 可能会创建大量线程,从而导致 OOM
                                ScheduledThreadPoolExecutor 主要用来在给定的延迟后运行任务,或者定期执行任务。
覆盖corepoolsize---否--corepoolsize是否小于当前工作线程数--否--当前值是否大于原值---是----队列是否有任务---是---创建worker线程去执行队列的任务--结束
                                        对idle线程发起中断,回收                           结束                                       结束

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值