并发编程第14篇,并发队列框架实战操作

并发队列框架实战操作

 

用户态与内核态之间的区别

 

内核态(Kernel Mode):运行操作系统程序,操作硬件Cpu的调度分配、内存、IO操作。

用户态(User Mode):运行用户程序

 

并发编程第14篇,并发队列框架实战操作

 

Synchronized升级重量锁优化过程

Synchronized 锁 默认是为轻量锁,慢慢升级为重量级锁,当如果线程没有获取锁的时候

会被阻塞等待,同时释放cpu执行权,而我们阻塞或者唤醒线程的过程是有系统内核实现的,所以如果Synchronized 升级为重量锁的时候是一个用户态切换为内核态过程,效率非常低。

 

异步打印日志的需求

在高并发的情况下,服务器端频繁的接收到请求,这时候因为打印日志本身操作是需要对IO做写的操作,写的操作操作有可能会暂停到打印日志的线程。

用户空间需要切换到内核空间,会导致用户空间阻塞的。

异步日志框架源码分析

 AsyncAppender中AsyncAppenderBase类, 创建了一个Worker线程异步的从队列中获取日志,并且异步写入到硬盘中。

并发编程第14篇,并发队列框架实战操作

 

 

并发编程第14篇,并发队列框架实战操作

基于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/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

@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();

  

    }

}

 

 

并发编程课程总结

 如何优化多线程

  1. 锁建议做好使用CAS或者自旋锁 ,不建议为悲观锁
  2. Synchronized锁使用偏向锁或者轻量锁 减少锁持有时间
  3. 降低锁的粒度采用 分段锁
  4. 使用fork jojn 并行提高多线程的效率
  5. 减少多线程上下文的切换 使用多核处理器或者是线程池

本章主要说并发队列都运用,并发队列加netty还能做消息中间件,那么并发队列都底层又是怎么实现都呢?

每一行代码都有它的涵义,多问一句为什么;别怕,理清思路,一切代码都是数据的流动和转化,耐心一点,慢慢积累!一起加油!!!