Appearance
什么是线程安全,造成线程安全的本质是什么
如果一个对象可以被安全地被多个线程同时使用,那么它就是线程安全的
并发问题的源头:
- 可见性:
- CPU计算结果不可能永远及时刷新到主存上,导致读取主存不一定能拿到最新的数据
- 原子性:
- 一个或多个操作在CPU执行过程中不被中断的特性称为[原子性]
- 线程切换导致
- 有序性:
- 为了提升性能,只要最终结果与顺序执行结果相等,编译器和处理器通常会对指令序列进行重新排列
- 编译器优化导致
Java中有哪几种方式来创建线程执行任务
- 继承Thread类
- 实现Runnable接口
- 由于java是单继承的性质,直接继承Thread类之后就不能继承其他类,所以通常情况下,实现Runnable比较合理.
- Thread类其实也是实现了Runnable接口
- 实现Callable接口(该接口继承了Runnable和Future接口),然后创建一个FutureTask对象,创建一个Thread对象,通过Thread运行之后,可以从实现Callable的这个对象获得执行结果.
- 通过线程池来执行Runnable对象,线程池会根据线程池类型分配线程执行任务.
- 在调用实现类的start()方法后,会启动一个线程分支,在JVM开辟一个新的栈空间,在分配到cpu资源后,会调用该实现类的run方法。
线程的生命周期状态
- new Thread()
- NEW 状态,线程被创建出来单没有被调用start()
- Thread.start()
- RUNNABLE, 运行状态,调用了start()
- RUNNING 运行中状态
- READY 就绪状态
- RUNNABLE, 运行状态,调用了start()
- 未获取到锁-->BLOCKED状态
- Object.wait() , Object.join() , LockSuport.park()
- WAITING 状态
- 在waiting状态调用Object.notify(),Object.notifyAll(),LookSupport.unpark() 或者 join的线程执行完毕时,从waiting状态回到running状态
- TERMINATED
- 终止状态,表示该线程已经运行完毕
ThreadLocal有哪些应用场景?它底层是如何实现的
- ThreadLocal 是Java 中所提供的线程本地存储机制,可以利用该机制将数据 缓存在某个线程内部,该线程可以在任意时刻,任意方法中获取缓存的数据
- ThreadLocal 底层是通过ThreadLocalMap来实现的
- 每个Thread对象中都存在一个ThreadLocalMap
- Map的key为ThreadLocal对象,Map的value为需要缓存的值
- 如果在线程池中使用ThreadLocal,在使用完之后要主动抢先用ThreadLocal的remove方法,不然会造成内存泄露
- ThreadLocal的应用场景之一是连接管理,一个线程持有一个连接,这样就不会造成多个线程共享一个连接.
为什么不建议使用Executors来创建线程池
- 因为Executors创建线程池的容器是无界阻塞队列LinkedBlockingQueue,如果任务过多,就会造成内存溢出.
- 使用Executors创建线程池不能够自定义线程名字,通常使用几号线程池几号线程,这样不容易通过日志排查问题.
- 建议通过ThreadPoolExecutor来定义线程池.