目录
2.1 什么是 Java 内存模型,以及Java内存模型的作用?
一、线程和并发
1.1 线程介绍
1)任务调度和分配的基本单位,一个进程内有多个线程,共享进程中的资源,减少进程切换的时空开销,提升并发效率。
2)线程的五个状态:NEW、RUNNABLE、BLOCKED、WAIT/TIMED_WAITING、TERMINATED。
3)线程同步的方式:
通过 Object 的 wait() 和 notify();(用在sychronized锁中) |
通过 Condition 的 awiat() 和 signal();(用在Reentrant Lock锁中) |
通过阻塞队列; |
通过线程池的Callback回调; |
通过同步辅助类CountDownLatch; |
通过同步辅助类CyclicBarrier; |
信号量 Semphare; |
1.2 线程安全,实现线程安全的主要方法
多个线程访问某个类,始终保持正确的行为。
1、互斥同步(悲观锁);
2、非互斥同步(乐观锁)。
1.3 线程的优点和缺点?
优点:1)充分利用多核 CPU 的资源,提升系统效率;
2)建模简单;
3)异步事件的简单处理。
缺点:1)安全性问题(程序执行顺序);
2)死锁;
3)资源消耗过高、吞吐率过低、响应不灵敏等。
1.4 并发级别
1)阻塞:sychronized关键字;
2)无饥饿:公平队列;
3)无障碍:一致性标记;
4)无锁:CAS;
5)无等待:CopyOnWriteArrayList;
二、Java 内存模型
2.1 什么是 Java 内存模型,以及Java内存模型的作用?
Java 内存模型定义各个变量的访问规则,由 violate、final、sychronized 关键字实现原子性、可见性、有序性,以及 happen before 原则组成,happen before 原则:程序顺序规则、管程规则、violate规则、线程start()规则、线程join()规则、传递性规则。
2.2 Happen Before 原则
1、程序顺序规则:
2、管程规则:
3、violate规则:
4、线程start()规则:
5、线程join()规则:
6、传递性规则:
三、锁机制
3.1 内置锁:sychronized
JVM 基于 Monitor 对象,利用 monitorenter 和 monitorexit 这两个字节码指令实现。
3.2 可重入锁:ReetrantLock
ReetrantLock 底层实现原理AbstractQueuedSynchronizer(抽象队列同步器):核心数据结构:双向链表 + state(锁状态)、底层操作:CAS。
创建 ReentrantLock 的对象的时候 ,其实是创建了一个 NonfairSync() 对象,NonfairSync类是静态内部类,他继承了Sync,Sync继承了AbstractQueuedSynchronizer。
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
3.3 锁
重量级锁:Synchronized 的重量级锁是通过对象内部的一个叫做监视器锁(monitor)来实现的,监视器锁本质又是依赖于底层操作系统的Mutex Lock(互斥锁)来实现的。而操作系统实现线程之间的切换需要从用户态转换到核心态,这个成本非常高,状态之间的转换需要相对比较长的时间。
1、自旋锁:
2、轻量级锁:
3、所偏向:
4、锁消除:是指虚拟机即时编译器(JIT)在运行时,对一些代码上要求同步,但是检测到不可能发生数据竞争的锁进行消除。
5、锁粗化:
3.4 锁优化
1、缩小锁的范围;
2、减小锁的粒度:即使用对个对象内置锁。
3.5 死锁的四个条件和死锁避免
因为申请资源而互相等待其他线程释放资源,
死锁的四个必要条件:1)互斥;2)占有并等待;3)不剥夺;4)循环等待。
破坏死锁的四个必要条件之一,以及银行家算法。
3.6 synchronized 和 Lock 锁的区别?
1、synchronized 适合线程竞争不激烈的时候;Lock 适合线程竞争激烈的时候。
2、Lock 是可中断的,可设置为公平锁,申请限时等待;
3、synchronized 是对象的内置锁;Lock 是 ReetrantLock 类可重入锁;
4、synchronized 可用来修饰方法和代码块,托管给JVM执行;Lock 需要通过代码实现,一般在 try/catch、finally 代码块中手动编写和释放;
3.7 sleep() 和 wait() 方法的区别?
1、sleep()是Thread类的方法,用于控制自身的流程;wait() 是 Object() 类的方法用于线程同步;
2、sleep()不释放锁;wait()释放锁;
3、sleep()可以在任何地方;wait()只能在 sychronized 修饰的方法和代码块中。
四、并发容器类
4.1 同步容器类
1)Voctor;
2)HashTable。
4.2 同步并发类
1) 点击蓝色字体,跳转到详细介绍界面,ConcurrentHashMap;
2)CopyOnWriteArrayList;
写时复制, 在往集合中添加数据的时候,先拷贝存储的数组,然后添加元素到拷贝好的数组中,然后用现在的数组去替换成员变量的数组(就是get等读取操作读取的数组)。多读取,少添加。
3)ReentrantReadWriteLock:每次只能有一个写线程,但是可以有多个线程并发地读数据。
/**
* 基于读写锁和 CountDown 闭锁实现读写锁和 Lock 锁的比较
* @author TSjia
*
*/
public class ReadWriteLockDemo {
private static Lock lock = new ReentrantLock();
private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private static Lock readLock = readWriteLock.readLock();
private static Lock writeLock = readWriteLock.writeLock();
public static CountDownLatch end = new CountDownLatch(20);
private int value;
public Object handleRead(Lock lock) throws InterruptedException {
try {
lock.lock();
Thread.sleep(1000);
return value;
} catch (Exception e) {
e.printStackTrace();
}finally {
end.countDown();
lock.unlock();
}
return 0;
}
public void handleWrite(Lock lock, int index) throws InterruptedException {
try {
lock.lock();
Thread.sleep(1000);
value = index;
} catch (Exception e) {
e.printStackTrace();
}finally {
end.countDown();
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
final ReadWriteLockDemo demo = new ReadWriteLockDemo();
Runnable readRunnable = new Runnable() {
@Override
public void run() {
try {
demo.handleRead(readLock);
// demo.handleRead(lock);
} catch (Exception e) {
e.printStackTrace();
}
}
};
Runnable writeRunnable = new Runnable() {
@Override
public void run() {
try {
demo.handleWrite(writeLock, new Random().nextInt());
// demo.handleWrite(lock, new Random().nextInt());
} catch (Exception e) {
e.printStackTrace();
}
}
};
long date = System.currentTimeMillis();
for(int i=0; i<18; i++) {
new Thread(readRunnable).start();
}
for(int i=18; i<20; i++) {
new Thread(writeRunnable).start();
new Thread(writeRunnable).start();
}
end.await();
System.out.println("耗费时间:" + (System.currentTimeMillis()-date));
}
}
4)阻塞队列和生产者和消费者模型
有界缓冲区(bounded-buffer)问题,阻塞队列 ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue(无界队列)。
PriorityBlockingQueue是一个无界队列,它没有限制,在内存允许的情况下可以无限添加元素;它又是具有优先级的队列,是通过构造函数传入的对象来判断,传入的对象必须实现comparable接口。
/**
* 队列 + sychronized + wait()/notifyAll()实现生产者和消费者
* @author TSjia
*
*/
public class ProduceAndConsumerDemo {
public static Object lock = new Object();
static class Produce implements Runnable {
Queue<Integer> queue = null;
public Produce(Queue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
synchronized (lock) {
while(queue.size() == 5) {
lock.wait();
}
Integer i = new Random().nextInt(100);
System.out.println("生产者--生产:" + i);
queue.offer(i);
lock.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class Consumer implements Runnable {
Queue<Integer> queue = null;
public Consumer(Queue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
synchronized (lock) {
while(queue.size() == 0) {
lock.wait();
}
System.out.println("消费者--取队列首元素:" + queue.poll());
lock.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<Integer>();
Produce produce = new Produce(queue);
Consumer consumer = new Consumer(queue);
for(int i=0; i<100; i++) {
Thread t1 = new Thread(produce);
t1.start();
Thread t2 = new Thread(consumer);
t2.start();
}
}
}
4.3 同步工具类
1)闭锁:CountDownLatch;
用于控制主线程等待其他线程执行结束,再继续执行。
public class CountDownLatchDemo2 {
public static void main(String[] args) throws InterruptedException {
CountDownLatchDemo2 bisuo = new CountDownLatchDemo2();
long threadtime = bisuo.timetasks(10);
double ans = (double)threadtime / 1000000000;
System.out.println("Thread time:" +ans + "s");
}
public long timetasks(int nThreads) throws InterruptedException {
final CountDownLatch startGate = new CountDownLatch(1);
final CountDownLatch endGate = new CountDownLatch(nThreads);
for (int i=0; i< nThreads; i++){
Thread t = new Thread(){
public void run(){
try{
startGate.await(); //wait the startGate count down to zero, then run.
try{
Thread.sleep(1000);
System.out.println("Thread Id: " + this.getId());
} finally {
endGate.countDown();
}
} catch (InterruptedException ignored){ }
}
};
t.start();
}
long start = System.nanoTime(); //单位纳秒
startGate.countDown();
endGate.await(); //wait the endGate count down to zero, then run.
long end = System.nanoTime();
return end - start;
}
}
2)Future;
核心思想时异步调用,当调用一个耗时方法时,后台运行该方法,主线程继续处理其他任务,再获得耗时方法的结果。
// Callable 具体实现
public class TrueData implements Callable<String>{
private String queryStr;
public TrueData(String queryStr) {
this.queryStr = queryStr;
}
@Override
public String call() throws Exception {
String result = "";
if(queryStr.equals("诸葛亮")) {
try {
System.out.println("诸葛亮还没睡醒,请等待。。。");
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
result = "诸葛亮刚刚睡醒!";
}
else
result = "我不是诸葛亮,我是他的弟弟诸葛均";
return result;
}
}
// FutureMain 函数
public class FutureMain {
public static void main(String[] args) throws InterruptedException, ExecutionException{
// submit提交一个实现 Callable 接口的任务,并且返回封装了异步计算结果的Future。
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<String> future = executor.submit(new TrueData("诸葛亮"));
System.out.println("到达卧龙岗");
System.out.println("三顾茅庐 :" + future.get());
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("三顾茅庐 :" + future.get());
executor.shutdown();
}
}
3)信号量:Semaphore
指定多个线程同时访问同一个资源。
public class SemaphoreDemo {
public static void main(String[] args) {
// 只能5个线程同时访问
final Semaphore semp = new Semaphore(5);
for (int index = 0; index < 20; index++) {
final int NO = index;
new Thread() {
public void run() {
try {
semp.acquire(); // 获取许可
System.out.println("Accessing: " + NO);
Thread.sleep(1000); // 模拟实际业务逻辑
semp.release(); // 访问完后,释放
} catch (InterruptedException e) {
}
}
}.start();
}
}
}
4)栅栏:CyclicBarrier
实现多个线程相互等待,直到所有线程都结束之后,再运行后续程序。
class CyclicBarrierWorker implements Runnable {
private int id;
private CyclicBarrier barrier;
public CyclicBarrierWorker(int id, final CyclicBarrier barrier) {
this.id = id;
this.barrier = barrier;
}
@Override
public void run() {
try {
System.out.println(id + " th people wait");
barrier.await(); // 大家等待最后一个线程到达
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}
public class TestCyclicBarrier {
public static void main(String[] args) {
int num = 10;
CyclicBarrier barrier = new CyclicBarrier(num, new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("go on together!");
}
});
for (int i = 1; i <= num; i++) {
new Thread(new CyclicBarrierWorker(i, barrier)).start();
}
}
}
4.4 Executor
1)继承关系
2)四种常见的线程池:
CachedThreadPool:可缓存的线程池;
SecudleThreadPool:周期性执行任务的线程池;
SingleThreadPool:只有一条线程来执行任务;
FixedThreadPool:定长的线程池。
3)ThreadPoolExecutor 类构造函数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)