用户态与内核态之间的区别
内核态(Kernel Mode):运行操作系统程序,操作硬件Cpu的调度分配、内存、IO操作。
用户态(User Mode):运行用户程序
[图片上传失败...(image-98ab82-1596413465864)]
Synchronized升级重量锁优化过程
Synchronized 锁 默认是为轻量锁,慢慢升级为重量级锁,当如果线程没有获取锁的时候
会被阻塞等待,同时释放cpu执行权,而我们阻塞或者唤醒线程的过程是有系统内核实现的,所以如果Synchronized 升级为重量锁的时候是一个用户态切换为内核态过程,效率非常低。
异步打印日志的需求
在高并发的情况下,服务器端频繁的接收到请求,这时候因为打印日志本身操作是需要对IO做写的操作,写的操作操作有可能会暂停到打印日志的线程。
用户空间需要切换到内核空间,会导致用户空间阻塞的。
异步日志框架源码分析
AsyncAppender中AsyncAppenderBase类, 创建了一个Worker线程异步的从队列中获取日志,并且异步写入到硬盘中。
[图片上传失败...(image-8fec0c-1596413465863)]
[图片上传失败...(image-6a9ba9-1596413465863)]
基于ArrayBlockingQueue手写异步框架
|
public class LogBlockingQueue { private static final int maxCapacity = 20000; private static ArrayBlockingQueue<String> logBlockingQueue = new ArrayBlockingQueue<String>(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/mayikt.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("mayikt"); } }
|
|
@Component @Slf4j public class LogMonitor { public void start() { log.info("****开启异步采集日志,存储到硬盘中****.."); new Worker().start(); } class Worker extends Thread { @Override public void run() { for (; ; ) { String mtLog = LogBlockingQueue.getLog(); if (!StringUtils.isEmpty(mtLog)) { LogException.writeErrorMsg(mtLog); log.info("****异步的将****mtLog:{}****,写入到银盘中****.", mtLog); } } } } }
|
|
@Slf4j @Component public class StartListener implements ApplicationListener<ApplicationReadyEvent> { @Autowired private LogMonitor logMonitor; @Override public void onApplicationEvent(ApplicationReadyEvent event) { log.info(">>****项目启动成功****<<<"); logMonitor.start(); } }
|
并发编程课程总结
** 如何优化多线程**
-
锁建议做好使用CAS或者自旋锁 ,不建议为悲观锁
-
Synchronized锁使用偏向锁或者轻量锁 减少锁持有时间
-
降低锁的粒度采用 分段锁
-
使用fork jojn 并行提高多线程的效率
-
减少多线程上下文的切换 使用多核处理器或者是线程池
网友评论