并发队列框架实战操作
用户态与内核态之间的区别
内核态(Kernel Mode):运行操作系统程序,操作硬件Cpu的调度分配、内存、IO操作。
用户态(User Mode):运行用户程序
Synchronized升级重量锁优化过程
Synchronized 锁 默认是为轻量锁,慢慢升级为重量级锁,当如果线程没有获取锁的时候
会被阻塞等待,同时释放cpu执行权,而我们阻塞或者唤醒线程的过程是有系统内核实现的,所以如果Synchronized 升级为重量锁的时候是一个用户态切换为内核态过程,效率非常低。
异步打印日志的需求
在高并发的情况下,服务器端频繁的接收到请求,这时候因为打印日志本身操作是需要对IO做写的操作,写的操作操作有可能会暂停到打印日志的线程。
用户空间需要切换到内核空间,会导致用户空间阻塞的。
异步日志框架源码分析
AsyncAppender中AsyncAppenderBase类, 创建了一个Worker线程异步的从队列中获取日志,并且异步写入到硬盘中。
基于ArrayBlockingQueue手写异步框架
public class LogBlockingQueue {private static final int maxCapacity = 20000;private static ArrayBlockingQueuelogBlockingQueue =new ArrayBlockingQueue(maxCapacity);/** * 添加log * * @param log* @return*/public static boolean addLog(String log) {return logBlockingQueue.offer(log); }/** * 查询log * * @param* @return*/public static String getLog() {return logBlockingQueue.poll(); } }
|
/** * 异步写日志文件*/public class LogException {private static final String path = "e://code/abc.log";public static void writeErrorMsg(String content) {writeErrorMsg(path, content); }/** * @param path* @throws IOException * @将错误信息输入到txt中*/public static void writeErrorMsg(String path, String content) { File F = new File(path);//如果文件不存在,就动态创建文件if (!F.exists()) {try { F.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } FileWriter fw = null; String writeDate = "时间:" + getNowDate() + "---" + "error:" + content;try {//设置为:True,表示写入的时候追加数据fw = new FileWriter(F, true);//回车并换行fw.write(writeDate + "\r\n"); } catch (IOException e) { e.printStackTrace(); } finally {if (fw != null) {try { fw.close(); } catch (IOException e) { e.printStackTrace(); } } } }/** * @return* @获取系统当前时间*/public static String getNowDate() { Calendar D = Calendar.getInstance();int year = 0;int moth = 0;int day = 0; year = D.get(Calendar.YEAR); moth = D.get(Calendar.MONTH) + 1; day = D.get(Calendar.DAY_OF_MONTH); String nowDate = String.valueOf(year) + "-" + String.valueOf(moth) + "-" + String.valueOf(day);return nowDate; }public static void main(String[] args) {writeErrorMsg("abc"); } }
|
@Component @Slf4jpublic class LogMonitor {public void start() {log.info("开启异步采集日志,存储到硬盘中..");new Worker().start(); }class Worker extends Thread {@Overridepublic void run() {for (; ; ) { String mtLog = LogBlockingQueue.getLog();if (!StringUtils.isEmpty(mtLog)) { LogException.writeErrorMsg(mtLog);log.info("异步的将mtLog:{},写入到银盘中.", mtLog); } } } } }
|
@Slf4j @Componentpublic class StartListener implements ApplicationListener {@Autowiredprivate LogMonitor logMonitor;@Overridepublic void onApplicationEvent(ApplicationReadyEvent event) {log.info(">>项目启动成功<<);logMonitor.start(); } }
|
并发编程课程总结
如何优化多线程
锁建议做好使用CAS或者自旋锁 ,不建议为悲观锁
Synchronized锁使用偏向锁或者轻量锁 减少锁持有时间
降低锁的粒度采用 分段锁
使用fork jojn 并行提高多线程的效率
减少多线程上下文的切换 使用多核处理器或者是线程池
本章主要说并发队列都运用,并发队列加netty还能做消息中间件,那么并发队列都底层又是怎么实现都呢?
每一行代码都有它的涵义,多问一句为什么;别怕,理清思路,一切代码都是数据的流动和转化,耐心一点,慢慢积累!一起加油!!!