目录

Life in Flow

知不知,尚矣;不知知,病矣。
不知不知,殆矣。

存档: 2020 年 03 月 (19)

ThreadLocal

ThreadLocal 适用场景 场景 1:每个线程需要一个独享的对象(通常是工具类,典型需要使用的类有 SimpleDateFormat、Random、工具类线程不安全,所以每个线程需要拥有自己独立的工具类) * 每个 Thread 内有自己的实例副本,不共享 SimpleDateFormat 进化过程 1. 2个线程分别用自己的 SimpleDateFormat 2. 10个线程变为for循环,10个线程new 了10个SimpleDateFormat 3. 1000个线程,必然用线程池(否则消耗太多内存) 4. static SimpleDateFormat ,所有线程公用同一个 SimpleDateFormat 对象 (发现线程不安全) 5. 用 synchronized 加锁修复了线程安全性,但是影响了并发能力。 6. ThreadLocal 登场。线程池中的每个线程中,都有一个 SimpleDateFormat 对象副本,提高并发能力,还不会像 synchronized 那样带来线程安全问题 示例:两个线程分别打印出自己的日期 (用 synchronized 加锁,修复....

死锁

死锁  发生在并发中,发生在两个线程或多个线程之间。  互不相让:当两个(或更多)线程(或进程)相互持有对方所需要的资源,又不主动释放,导致所有人都无法继续前进,导致程序陷入无尽的阻塞(等待状态),这就是死锁。 多个线程造成死锁的情况  如果多个线程之间的依赖关系是环形,存在环路的锁的依赖关系,那么也可能会发生死锁。 死锁的影响 死锁的影响在不同系统中是不一样的,这取决于系统对死锁的处理能力。 * 数据库中:检测并放弃事务(事务之间发生死锁) * JVM中:无法自动处理 几率不高但危害大 不一定发生,但是遵循“墨菲定律”。 一旦发生,多是高并发场景,影响用户多。 整个系统崩溃,子系统崩溃、性能降低。 压力测试无法找出所有潜在的死锁。(死锁和并发量只是一个正相关的关系,并不是必然的关系,所以无法通过增加并发量来模拟出死锁,也无法保证高并发的情况下可以 100% 的模拟出死锁。) 发生死锁的例子 最简单的情况 /** * 描述: 必定发生死锁的情况 */ public class MustDeadLock implements Runnable { int flag = 1;....

Java 内存模型

从 Java 代码到 CPU 执行 Java 代码(IDE) javac 命令将源代码编译成 *.class (字节码)文件。 JVM 会根据操作系统和 CPU 平台的差异,将同样的字节码解释成不同的机器指令,无法保证并发安全的效果一致。 CPU 运行机器指令(程序的执行)。  基于并发安全性的考虑,需要制定一套规范、原则,用统一转化过程和结果,保证程序并发执行的安全性。 JVM 内存结构  Java 虚拟机的运行时区域相关。 方法区(Method Area)  是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。 堆(heap)  Java 堆是线程共享的。在一般情况下,堆可以说是 Java 内存中最大的内存区域。其存放了对象实例,几乎所有的对象实例在这里存储。(这里说是几乎,是因为 JIT 优化的存在,可能会有对象不在堆上分配,而在栈上进行分配)。 Java 虚拟机栈(VM stack)  用于作用于方法执行的一块 Java 内存区域。每个方法在执行的同时都会创建一个栈帧(Stack Framel):用于存储局部变量表、操....

线程异常 UncaughtException

线程未捕获异常应该如何处理?  UncaughtException 专门用于处理线程未捕获的异常。能检测出线程未捕获异常而终止的情况。  主线程可以轻松的发现异常,子线程却不行,子线程即使抛出异常,主线程也不受影响。  子线程异常无法用传统方法捕获。 示例:主线程可以轻松的发现异常,子线程却不行,子线程即使抛出异常,主线程也不受影响。 /** * 描述: 单线程,抛出,处理,有异常堆栈 * 多线程,子线程发生异常,会有什么不同? * 子线程抛出异常,主线程并不会中断 * * Exception in thread "Thread-0" java.lang.RuntimeException * at com.xdclass.couponapp.test.uncaughtexception.ExceptionInChildThread.run(ExceptionInChildThread.java:18) * 0 * 1 * 2 */ public class ExceptionInChildThread implements Runnable { public static void m....

线程中的属性

线程各属性总览 线程Id、线程名字  线程是从1开始的,除主线程外,JVM虚拟机会开启一些额外的进程:Finalizer、Reference Handler、Signal Dispatcher、Attach Listener /** * 描述: ID从1开始,JVM运行起来后,我们自己创建的线程的ID早已不是2 * * 主线程id 1 * t1的id 20 * t1的名字 Thread-0 * t1的名字 NewThreadT1 */ public class Id { public static void main(String[] args) { Thread t1 = new Thread(); System.out.println("主线程id " + Thread.currentThread().getId()); System.out.println("t1的id " + t1.getId()); System.out.println("t1的名字 " + t1.getName()); //修改t1的名字 t1.setName("NewThreadT1"); System....