线程整理文档
1、Java的线程状态源码中为啥没有RUNNING状态
public class Thread implements Runnable {//省略...public enum State {NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED;}//省略...
}
CPU的时间片很短,一般也就10-20毫秒左右,在一秒钟之内一个线程可能一部分时间处于就绪状态,一部分时间处于运行状态;给线程定义出RUNNING状态其实是不准确的;
2、wait() 和 sleep() 的区别?
- sleep()方法,在休眠时间结束后,会自动的被唤醒。而wait()进入到的阻塞态,需要被 notify/notifyAll手动唤醒。
- wait()会释放自己持有的指定的锁标记,进入到阻塞态。 sleep()进入到阻塞态的时候,不会释 放自己持有的锁标记。
3、 创建线程的方式
请用两种不同的方式创建并启动线程,分别打印10次的"Hello from Thread-1"和"Hello from Thread-2"。
4、Callable和FutureTask使用
创建一个实现 Callable 接口的任务,计算1-1000的质数个数。
5、线程状态控制(考察sleep和join两个方法)
创建一个线程,实现以下功能:
- 线程启动后运行5秒
- 在第3秒时暂停2秒
- 然后继续运行剩余时间
- 主线程等待该线程结束后再退出
6、线程安全问题演示
创建一个银行账户类 BankAccount,包含余额字段和存钱、取钱方法。创建多个线程同时操作同一个账户,演示线程安全问题。
7、ReentrantLock和synchronized有什么不同(面试题)
- 第一点:
- ReentrantLock可以提供公平+非公平两种特性,当ReentrantLock构造方法中指定了参数为true的时候,这个锁被确定为公平锁。而synchronized无法提供公平锁的特性
- 第二点:
-
ReentrantLock的加锁、解锁操作都是需要手动进行,而synchronized的话可以进行自动的加锁、解锁操作。synchronized可以有效避免加锁之后忘记解锁的情况。
-
当代码执行到synchronized修饰的代码块的时候,如果在同步代码块内部发生了异常,没有及时处理的话,会提前退出并且让线程释放锁。而ReentrantLock无法做到立刻解锁,因此,unLock()的解锁操作一定要在finally代码块当中,避免加锁之后忘记解锁的情况。
-
- 第三点:
-
synchronized无法提供lock.tryLock()这样的尝试获取锁的特性,而ReentrantLock可以提供。
-
线程如果在指定的时间之内无法获取到锁,或者锁已经被占用了,那么lock.tryLock()可以有效减少线程阻塞等待的情况,或者减少阻塞等待的时间。而synchronized只会让无法获取到锁的线程"死等"。直到获取到锁的线程释放锁
-
- 第四点:
- ReentrantLock可以提供中断式加锁。 ReentrantLock在调用lock.lockInterruptibly()时候,可以让获取不到锁,进入阻塞等待的线程被提前"唤醒",但是synchronized不可以。具体的操作已经在上面解释了。
生产者消费者模式当中,如果缓冲区的满了,那么生产者将不再进行生产,这个时候他将进入wait()等待队列,因为只有这样他才会释放锁,消费者才可以获取锁从缓冲区拿
死锁概念
死锁的产生:
死锁是指两个或多个线程无限期地等待对方持有的资源而导致的一种阻塞现象。
互斥;不可抢占;占有和等待;循环等待;
常见死锁原因:
1)竞争同一把锁是发生死锁
2)多个锁的嵌套导致死锁
死锁的解决方案:
1.避免使用多把锁
2.统一锁的获取顺序
3.使用超时等待锁
4.检查死锁
ReentrantLock
reentrantlock是Java并发包中的一个可重入锁的实现;
1)可重入性
持有该锁的线程可以再次获得这把锁,而不会发生死锁,每次成功获取都会增加次数,相应 的释放都会减少计数,当计数为零时,锁才会真正释放给其它等待线程
2)公平性
公平锁(true):
按照线程请求锁的顺序进行排队,先请求的线程优先获取锁,公平锁倾向与减少线程饥饿现象,
但可能降低系统的整体吞吐量
非公平锁(默认,false):
不保证线程按照请求锁的顺序分配锁,允许后来的线程“插队”获取锁,非公平锁在某些场景下可能提供更高的性能,但可能增加线程饥饿的风险。
3)显示锁操作
与synchronized关键字(隐式锁操作)不同,ReentrantLock需要显示地调用方法来获取和释放锁
4)条件变量(Condition)
生产者消费者设计模式
生产者消费者模型是一个非常经典的多线程并发协作的模型
生产者消费者模式的优点
1.解耦
由于有缓冲区的原因生产者和消费者之间不直接依赖,耦合度降低。
2.支持并发
由于生产者和消费者是两个独立个体,如果不管缓冲区的容量问题是可以一个一直放一个一直取的,但是这种是hi出现数量异常的情况,所以在案例中用的苹果的买卖是同步执行的生产者和消费者模型;
3.支持忙闲不均
缓冲区的的另一个好处,当生产过快时,消费者来不及处理,未处理的数据可以在缓冲区中,等消费者处理掉其他数据时,在从缓冲区中取数据来处理
生产者消费者模式所遵循的规则
1.生产者仅仅在缓冲区未满时生产,缓冲区满则停止生产。
2.消费者仅仅在缓冲区有产品时才能消费,缓冲区为空则停止消费
3.当消费者发现缓冲区没有可消费的产品时会通知生产者。
4.当生产者生产出可消费的产品时,应该通知等待的消费者去消费。
线程池用法
线程池的简介:
线程池就是一个容器,里面存储了若干个线程。
线程池的工作原理:
线程池中的所有线程可以分为两部分:核心线程和临时线程。
3.当消费者发现缓冲区没有可消费的产品时会通知生产者。
4.当生产者生产出可消费的产品时,应该通知等待的消费者去消费。