悲观锁总是假设最坏的情况,认为共享资源每次被访问的时候就会出现问题,所以每次在获取资源操作的时候都会上锁,这样其它线程想拿到这个资源就会阻塞,一直到锁被上一个执行者释放。也就是说,共享资源每次只给一个线程使用,其它线程阻塞,用完后再吧资源转让给其它线程【synchronized 和 ReentrantLock 就是悲观锁思想的实现】
乐观锁总是假设最好的情况,认为共享资源每次被访问的时候不会出现问题,线程可以不停的执行,无需加锁也无需等待,只是在提交修改的时候去验证对应的数据是否被其它线程修改了
sychronized 是 Java 中的一个关键字,主要是解决多个线程之间访问资源的同步性,可以保证被它修饰的方法或者代码块只能有一个线程在执行
synchronized void method() {
//业务代码
}
synchronized static void method() {
//业务代码
}
synchronized(this) {
//业务代码
}
不互斥。因为访问静态同步方法占用的锁是当前类的锁,而访问非静态同步方法占用的锁是当前实例对象的锁
不可以,因为构造方法本身就属于线程安全的,不存在同步的构造方法一说
ReentrantLock 是什么?
ReentrantLock 实现了 Lock 接口,和 synchronized 关键字类似。不过 ReentrantLock 更灵活、更强大,增加了轮询、超时、中断、公平锁和非公平锁等高级功能。
ReentrantLock 里面有一个内部类 Sync,添加锁和释放锁的大部分操作实际上都是在 Sync 中实现的,Sync 存在公平锁(FairSync)和非公平锁(NonFairSync) 两个子类【ReentrantLock 默认使用的是非公平锁,也可以通过构造器来指定使用公平锁】
管理一系列线程的资源池,就是当有任务要处理的时候,直接从线程池中获取线程来处理,处理完以后并不会销毁,而是等待下一个任务
主要是为了减少每次获取资源的消耗,提高对资源的利用率
提交任务,判断核心线程是否满,没满就使用核心线程,满了就判断任务队列是否满,没满则加入队列,满了则判断临时线程是否满了,没满就创建临时线程来使用,满了就按照拒绝策略来处理
通过 ThreadPoolExecutor 提供的一些 set 方法【注意的是:setCorePoolSize(),程序运行的时候,如果调用了该方法,线程池会先判断当前工作线程是否大于设置的值,如果大于就会收回工作线程】
主要用在一些需要执行耗时任务的场景,避免程序一直在原地等着耗时任务执行完毕,执行效率太低。【简单理解就是:我有一个任务,提交给了 Future 来处理。任务执行期间我自己可以去做任何想做的事情,并且在着期间还可以取消任务以及获取任务的执行状态。一段时间之后,可以直接从 Future 取出任务执行结果】
Future 类是一个泛型接口,具有取消任务、判断任务是否被取消、判断任务是否已经执行完成、获取任务执行结果的功能
Callable 和 Future 有什么关系?
FutureTask 提供了 Future 接口的基本实现,常用来封装 Callable 和 Runnable,具有取消任务、查看任务是否执行完成以及获取任务执行结果的方法。ExecutorService.submit() 方法返回的就是 Future 的实现类 FutureTask【FutureTask 不光实现了 Future 接口,还实现了 Runnable 接口,因此可以作为任务直接被线程执行】
【FutureTask 有两个构造函数,可以传入 Callable 或者 Runnable 对象,传入 Runnable 对象也会在方法内部转换为 Callable 对象】