首页 > 技术文章 > 并发调试

jarvankuo 2019-11-28 23:43 原文

并发调试、工具、容器!

参考文献:

Tomcat7 性能优化,提高并发-NIO模式

彻底搞懂面试中被问到的spring的单例多线程问题

详细理解单例模式与多线程+阿里面试题+面试心得

volatile 关键字

  • volatile 关键字的作用(变量可见性、禁止重排序),不能保证原子性

  • 使用场景

    • 通常修饰状态(boolean和int)
    • 单纯的赋值

同步机制

  • 监视器锁(synchronized)

    悲观锁

  • 显示锁(ReentrantLock、ReadWriteLock)

    还提供了诸如可响应中断锁、可轮询锁请求、定时锁等避免多线程死锁的方法

  • 原子变量(AtomicInteger、AtomicLong、AtomicBoolean)

    乐观锁、CAS(比较提换)

  • volatile

  • 线程封闭(模拟单线程,规避多线程环境)

    不共享数据

    • 栈封闭
    • ThreadLocal

发令枪

CountDownLatch(线程计数器 )

static CountDownLatch cdl = new CountDownLatch(20);
...
	cdl.countDown();  // 此处要调用20次
...
cdl.await(); // 阻塞,countDown计数20次后才统一走下一步程序
// 类似发令枪,统一起跑

Tomcat7 和 Tomcat8 的默认IO模型区别

tomcat7默认使用BIO,一个请求对应一个线程,阻塞

tomcat8默认使用NIO,一个线程可处理多个请求,非阻塞

  • 启动NIO模式

    修改tomcat7为NIO

    <Connector port="8080"protocol="org.apache.coyote.http11.Http11NioProtocol"
    
            connectionTimeout="20000" redirectPort="8443"/>
    
  • 线程池

    默认的tomcat没有启用线程池,在tomcat中每一个用户请求都是一个线程,所以可以使用线程池提高性能。这里前台其实有一个调度线程,然后调度线程会放入线程池内,然后到到一定的时候线程池的任务变成工作线程

    放开配置文件的下面注释,并在Connector中指定执行器

    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
            maxThreads="150" minSpareThreads="4"/>
    
    <!-- executor="tomcatThreadPool"为上面的执行器 -->
    <Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   redirectPort="8443" />
    

spring 单例支持多线程并发

为什么局部变量不会受多线程影响?

  1. 对于那些会以多线程运行的单例类,例如Web应用中的Servlet,每个方法中对局部变量的操作都是在线程自己独立的内存区域内完成的,所以是线程安全的

  2. 局部变量不会受多线程影响

  3. 成员变量会受到多线程影响

  4. 对于成员变量的操作,可以使用ThreadLocal来保证线程安全

    在bean对象中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中

推荐阅读