JUC第一天:
回顾:JVM
1. JVM 体系结构
2. 能够解析每个结构的作用
3. 如何调优
堆:
新生区:
普通 GC
养老区:
Full GC
元空间:
4. GC : 分代收集算法!
新生区:复制算法!
养老区:标记清除!标记整理!
重点:
1. 什么是JUC {java.util.concurrent在并发编程中使用的工具类}!
进程:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
线程:通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程可以利用进程所拥有的资源,在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统多个程序间并发执行的程度。
Thread.State
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,(新建)
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,(准备就绪)
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,(阻塞)
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,(不见不散)
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,(过时不候)
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;(终结)
}
2. wait/sleep的区别!
wait 释放资源锁! Object
sleep 不释放资源锁!Thread
3. 并发(同一时刻多个线程在访问同一个资源,多个线程对一个点 春运抢票)
,并行!(多项工作一起执行,之后再汇总 做饭 准备食材和烹饪)
4. 编写卖票的案例!
5. lock 接口 来代替synchronized:
直接将synchronized lock.lock(); lock.unlock();
6. 拉姆达表达式:
操作符区分 : -> 左边:方法的参数 ,右边: 方法的实现!
基本语法:拷贝小括号(),写死右箭头->,落地大括号{...}
函数式接口表示:@FunctionalInterface 这个接口中只能有一个方法{抽象方法}!
函数式接口中能否有实现的方法?
7. 线程间通信:
一个线程对一个数+1 ,一个线程对一个数-1
两个线程操作的时候,没问题!
如果换成4个线程,则会出现2的情况!这种情况:虚假唤醒!
解决方案:将if判断条件改成while!
java8新版实现:
lock 接口 来代替synchronized:
lock.newCondition();
await() wait()
signalAll() notifyAll();
总结:
上午:
1. 面试题!
2. lock 接口的使用!
lock 接口 来代替synchronized
lock 接口 来代替synchronized:
lock.newCondition();
await() wait()
signalAll() notifyAll();
下午:
1. 线程定制化通信!
demo: AA打印5次,BB打印10次,CC打印15次
......来10轮
a. 线程操作资源类
b. 判断,干活,通知
实现思路:
1、有顺序通知,需要有标识位
2、有一个锁Lock,3把钥匙Condition
3、判断标志位
4、输出线程名+第几次+第几轮
5、修改标志位,通知下一个
lock 接口 来代替synchronized:
lock.newCondition();
await() wait()
signalAll() notifyAll();
signal() notify();
2. 集合类是不安全的
a. Vector;
b. Collections.synchronizedList(new ArrayList<>());
c. CopyOnWriteArrayList; 写时复制!
底层源码:原理
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
// 有位置选择!
public void add(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
if (index > len || index < 0)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+len);
Object[] newElements;
int numMoved = len - index;
if (numMoved == 0)
newElements = Arrays.copyOf(elements, len + 1);
else {
newElements = new Object[len + 1];
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index, newElements, index + 1,
numMoved);
}
newElements[index] = element;
setArray(newElements);
} finally {
lock.unlock();
}
}
在多线程的情况下:如果要写入,修改数据!CopyOnWriteArrayList; 相对要比Collections.synchronizedList(); 速度快,性能提升!
ArrayList ---> CopyOnWriteArrayList();
HashSet ---> CopyOnWriteArraySet();
HashMap ---> ConcurrentHashMap<>();
JUC 第二天:
回顾:
第一天:
面试题:
线程,进程
并发,并行
wait/sleep的区别!
lock 接口:
lock.lock();
try {
// 执行的代码块
}finally{
lock.unlock();
}
线程的通信:
java8新版实现:
lock 接口 来代替synchronized:
Condition c1 = lock.newCondition();
await() wait()
signal() notify()
signalAll() notifyAll()
集合安全类:
ArrayList ---> CopyOnWriteArrayList();
HashSet ---> CopyOnWriteArraySet();
HashMap ---> ConcurrentHashMap<>();
-
锁的八种情况: *****
1 标准访问,先打印短信还是邮件
2 停4秒在短信方法内,先打印短信还是邮件
3 新增普通的hello方法,是先打短信还是hello
4 现在有两部手机,先打印短信还是邮件
5 两个静态同步方法,1部手机,先打印短信还是邮件
6 两个静态同步方法,2部手机,先打印短信还是邮件
7 1个静态同步方法,1个普通同步方法,1部手机,先打印短信还是邮件
8 1个静态同步方法,1个普通同步方法,2部手机,先打印短信还是邮件a. 如果只有普通同步方法的时候! 执行顺序:按照代码写的顺序去执行! 当前锁的对象是 this! b. 如果有普通方法和同步方法的时候! 正常情况下:按照代码顺序执行,如果同步方法中有睡眠,则先执行普通方法! c. 当不是同一个对象调用普通的同步方法时: 本质:每次创建对象的时候,都会创建属于自己的锁!这个锁就是当前对象 this! d. 静态同步方法当前锁对象:Class.class
-
Callable接口
2.1 获得多线程的方法几种? *****
4种
(1)继承Thread类
(2)runnable接口
(3)Callable接口
(4)线程池
Callable函数接口2.2 FutureTask 是Runable 一个实现类!通常用它来计算一个比较耗时的任务! 计算未来任务!最终获取结果!****** 使用get();方法获取到计算结果!通常放在最后,并且只计算一次! 找到中间人:Runnable! Thread 构造函数 Thread(Runnable target, String name) FutureTask(Callable<V> callable)! // 实现了Runnable 接口 new Thread(()->{ phone.getHello(); },"BB").start(); FutureTask f = new FutureTask(()->{ }); new Thread(f,"FF").start(); 2.3 面试题:callable接口与runnable接口的区别?***** 答: (1)是否有返回值 callable 有 (2)是否抛异常 callable 有 (3)落地方法不一样,一个是run,一个是call callable -- call . 2.4 如何使用!***** // 创建一个FutureTask 这个需要实现一个callable 函数式接口 FutureTask<Integer> futureTask = new FutureTask<Integer>(()->{ System.out.println(Thread.currentThread().getName()+" come in callable"); Thread.sleep(1000); // 设置返回值 return 1024; }); // FutureTask 是Runnable 的实现类 new Thread(futureTask,"AA").start(); // 可以在调用结果之前判断当前任务是否已经完成!如果没用完成,则等待 while (!futureTask.isDone()){ System.out.println("等待....."); } System.out.println(futureTask.get());
-
JUC强大的辅助类 - 【了解】
3.1 CountDownLatch 减少计数 记录线程个数
countDownLatch.countDown(); // 线程数 减一
countDownLatch.await(); // 知道线程的个数为0 的时候,就不等待了。3.2 CyclicBarrier 循环栅栏 cyclicBarrier.await(); // 如果没有满足初始化值的时候,那么就会等待! 3.3 Semaphore 信号量 semaphore.acquire(); // 获取到资源 semaphore.release(); // 释放资源
JUC
下午:
1.ReentrantReadWriteLock 读写锁 -- 了解
readWriteLock.writeLock().lock();
readWriteLock.readLock().lock();
2.BlockingQueue *****
队列:先进先出
阻塞队列:
put: 添加元素
take: 获取元素
a. 当队列是空的,从队列中获取元素的操作将会被阻塞
b. 当队列是满的,从队列中添加元素的操作将会被阻塞
阻塞队列的应用场景:
线程池!
代码演示:
put();
take();
3.线程池:
简单定义:处理过程中将任务放入队列,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。
线程池优势:
线程复用;控制最大并发数;管理线程。*****
线程池种类:
第一种:Executors.newFixedThreadPool(10); 初始化线程池的大小.
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
第二种:Executors.newSingleThreadExecutor(); 一池,一线程!
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
第三种:Executors.newCachedThreadPool(); 执行异步短期任务,可扩容.
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
三种创建线程池的方式:底层都是new ThreadPoolExecutor();
用线程池:使用哪一种?都不用!
自定义线程池:
new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
JUC 第三天:
回顾:
1. 锁的八种状态
2. Callable 函数式接口 {创建线程四种方式之一!}
3. 阻塞队列:
4. 线程池:
5. 读写锁了解!
-
继续完成线程池知识:
1.1 深入了解ThreadPoolExecutor!它是一个class
// 创建线程池:如何确定当前核心线程池个数:
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
2, // 核心线程池
5, // 最大线程池
3L, // 空闲线程的存活时间
TimeUnit.SECONDS, // 空闲线程存活时间单位
new ArrayBlockingQueue<>(3), // 阻塞队列个数
Executors.defaultThreadFactory(), // 使用默认的线程池工程
new ThreadPoolExecutor.AbortPolicy() // 默认值:直接发生异常,阻止运行!
// new ThreadPoolExecutor.DiscardOldestPolicy() // 抛弃等待最久的任务,尝试加入新的任务!
// new ThreadPoolExecutor.CallerRunsPolicy() // 调用者执行任务!
// new ThreadPoolExecutor.DiscardPolicy() // 丢弃任务,没有任何异常!
);1.2 线程池底层工作原理:*****
1.3 线程池的拒绝策略:
条件:阻塞队列+最大核心线程池数已满!
new ThreadPoolExecutor.AbortPolicy() // 默认值:直接发生异常,阻止运行!
// new ThreadPoolExecutor.DiscardOldestPolicy() // 抛弃等待最久的任务,尝试加入新的任务!
// new ThreadPoolExecutor.CallerRunsPolicy() // 调用者执行任务!
// new ThreadPoolExecutor.DiscardPolicy() // 丢弃任务,没有任何异常! -
java8回顾:*****
2.1 四大函数式接口:
// 消费型:没有返回值!
// 复制小括号,写死右箭头,落地大括号!
Consumerconsumer = (t)->{
System.out.println(t);
};
consumer.accept("hello");// 供给型:没有参数! // Supplier T get(); Supplier<String> supplier = ()->{ return UUID.randomUUID().toString(); }; System.out.println(supplier.get()); // 函数式接口 // Function<T, R> R apply(T t) Function<Integer,Integer> function =(t)->{ return t*2; }; System.out.println(function.apply(6)); // 断定型接口 // Predicate<T> boolean test(T t); Predicate<String> predicate = (t)->{ return t.startsWith("f"); }; System.out.println(predicate.test("atguigu")); System.out.println(predicate.test("full outer join"));
2.2 Stream 流操作!
定义:对数据源的计算!
特点:
a. 不会存储元素
b. 经过操作不会改变原有的数据,而会产生新的数据源
c. 操作延迟的Stream 流演示! 1. 创建一个User对象。 java 中一个对象中应该有的 :属性,get,set 方法,构造方法。。。
-
分支合并框架: 了解
3.1 ForkJoinPool: 分支合并池 fork(); join();
3.2 ForkJoinTask: 完成某一项功能 get();
3.3 RecursiveTask: 递归任务:继承后可以实现递归(自己调自己)调用的任务 -
异步编排 *****
CompletableFuture : 异步处理,与FutureTask 功能类似!
异步无返回值:runAsync();
异步有返回值:supplyAsync();
接收上一个线程返回的结果集:whenComplete
处理异常:exceptionally
评论区