买了好久了,都开始落灰了,今天决定把他拿出来学习一下,书上一下demo是可以运用于实战的,这是我第二回学习这本书了,第一回参考的是martin录的视频学习高并发的,受益良多,这次买了书,决定看书学习
学习准备
源码下载地址:https://gitee.com/crazymaker/Java-high-concurrency-core-Programming-Volume-2-source-code
学习计划
1. 11月25号开始,每天10页,一共460页,预计花费两个月,预计1月25号结束
2. 每周记录一次进度
重点攻克
1. P92 注册JVM钩子函数自动关闭线程池
学习记录
static class DemoThread extends Thread {
//可以通过这种方式给线程赋线程名称
public DemoThread() {
super("Mall-" + threadNo++);
}
@Override
public void run() {
for (int i = 1; i < MAX_TURN; i++) {
Print.cfo(getName() + ", 轮次:" + i);
}
Print.cfo(getName() + " 运行结束.");
}
}
1. 通过继承Thread类可以实现多线程能更好的做到多个线程并发的完成各自的任务。访问各自的数据资源
2. 通过实现Runnable接口实现多线程,可以做到多个线程并发的完成同一个任务,访问同一份数据资源
这样可以将线程逻辑和业务数据进行有效分离
3. FutureTask 以 Callable入参, 实现了Runnable和 Future接口
jps -l 得到线程号
jstack pid 可打印出线程的状态
"sleepThread-3" #15 prio=5 os_prio=31 tid=0x00007f9e4a84b800 nid=0xa503 waiting on condition [0x00007000104fd000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.crazymakercircle.mutithread.basic.use.SleepDemo$SleepThread.run(SleepDemo.java:30)
4.线程默认不是守护的
5. 用户线程和JVM虚拟机线程、守护线程的关系
用户进程都结束了以后,JVM线程也随之终止,守护线程也终止
守护线程启动了之后再设置为守护线程会抛InterruptedException,
6. 线程进入就绪状态的几种方式
1. 调用start方法
2. 当前线程的执行时间片用完
3. 线程sleep操作结束
4. 对其他线程合入join操作结束
5. 等待用户输入结束
6. 线程争抢到对象锁
7. 当前线程调用yield方法让出CPU权限
7. 线程进入阻塞或者等待的状态,CPU的时间片都会让出,但是锁会不会被释放,会根据情况而定
8.Java线程的创建非常昂贵,需要JVM和OS配合才能完成大量的工作
//统计的是线程池的工作任务数量、总计的任务数量
while (true) {
Print.tco("- activeCount:" + executor.getActiveCount() +
" - taskCount:" + executor.getTaskCount());
sleepSeconds(1);
}
有两个工厂类,Executors是线程池工厂类,ThreadFactory是线程工厂类,用于创建线程
static public class SimpleThreadFactory implements ThreadFactory {
static AtomicInteger threadNo = new AtomicInteger(1);
//实现其唯一的创建线程方法
@Override
public Thread newThread(Runnable target) {
String threadName = "simpleThread-" + threadNo.get();
Print.tco("创建一条线程,名称为:" + threadName);
threadNo.incrementAndGet();
//设置线程名称
Thread thread = new Thread(target, threadName);
//设置为守护线程
thread.setDaemon(true);
return thread;
}
}
/**
* 自定义拒绝策略
*/
public static class CustomIgnorePolicy implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
// 可做日志记录等
Print.tco(r + " rejected; " + " - getTaskCount: " + e.getTaskCount());
}
}
最大线程数包含着核心工作线程数
优雅地关闭线程池:
shutDown()和shutDownNow()和awaitTermination()三个方法配合使用
shutDownNow()会stop所有线程,清空工作队列
CountDownLatch和AtomicInteger结合使用:
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(THREAD_COUNT);
AtomicInteger atomicInteger = new AtomicInteger(0);
ThreadPoolExecutor threadPool = ThreadUtil.getMixedTargetThreadPool();
for (int i = 0; i < THREAD_COUNT; i++) {
// 创建10个线程,模拟多线程环境
threadPool.submit(() -> {
for (int j = 0; j < 1000; j++) {
atomicInteger.getAndIncrement();
}
latch.countDown();
});
}
latch.await();
Print.tco("累加之和:" + atomicInteger.get());
}
AtomicInteger 主要通过CAS‘自旋 + volatile的方案实现
LongAdder 以空间换时间,热点分离,多线程访问的时候,通过Hash算法将线程映射到数组的一个元素进行操作,将数组的元素求和就是获取最终的value结果