├── .gitignore ├── Chapter12 Java内存模型与线程.md ├── Chapter2 运行时数据区域.md ├── Chapter3 垃圾收集器与内存分配策略.md ├── Chapter4 虚拟机性能监控与故障处理工具.md ├── Chapter6 类文件结构.md ├── Chapter7 虚拟机类加载机制.md ├── Chapter8 虚拟机字节码执行引擎.md ├── README.md ├── example.object ├── img ├── Cache Coherence.jpg ├── Class文件格式.jpg ├── Class文件的访问标志.jpg ├── GC Root Tracing.jpg ├── HotSpot JVM 1.6 GC .jpg ├── Java runtime data area.png ├── Java虚拟机提供的语言无关性.png ├── access object by handle.jpg ├── access object by pointer.jpg ├── mat.png ├── oom.png ├── 两个栈帧之间的共享数据.png ├── 双亲委派模型.png ├── 栈帧的概念结构.jpg ├── 类的生命周期.jpg └── 线程、主内存、工作内存之间的关系.png ├── nio-data.txt └── src └── com └── taomk └── understandingJVM ├── FutureTest.java ├── annotation ├── Client.java ├── GeetingAnnotationTest.java ├── Greeting.java ├── NameCheckProcessor.java └── NameChecker.java ├── autobox └── Test.java ├── blockqueue └── BlockingQueueTest.java ├── cache └── LocalCache.java ├── candy └── AutoPackage.java ├── concurrent ├── atomic │ └── AtomicStudy.java ├── cow │ ├── BlackListServiceImpl.java │ └── CopyOnWriteMap.java ├── executor │ ├── CachedThreadExecutorTest.java │ ├── FixedThreadExecutorTest.java │ ├── ScheduledThreadExecutorTest.java │ └── SingleThreadExecutorTest.java ├── forkjoin │ └── ForkJoinStudy.java ├── lock │ └── TestLocks.java ├── map │ ├── ConcurrentHashMapIteratorDemo.java │ └── ConcurrentHashmapStudy.java └── task │ └── consumeAndProducer │ ├── multi │ ├── Client.java │ ├── Consumer.java │ ├── Producer.java │ ├── Resource.java │ └── ResourceBy2Condition.java │ └── single │ ├── Client.java │ ├── Consumer.java │ ├── Producer.java │ ├── Resource.java │ └── ResourceByLock.java ├── encrypt ├── Base64.java ├── RSAEncrypt.java ├── RSASignature.java └── Test.java ├── forfun ├── HelloWorld.java └── Test.java ├── gc ├── Allocation.java ├── FinalizeEscapeGC.java └── ReferenceCountingGC.java ├── hashcode └── HashCodeAndEquals.java ├── innerClass └── Outter.java ├── interview ├── InterfaceWhitDefaultMethod.java ├── InterfaceWhitDefaultMethodImpl.java ├── ReverseSingleLinkedNode.java └── SortedByValueMapDemo.java ├── java8 ├── lambda │ ├── ComparatorFactory.java │ ├── defaultMethod │ │ └── DefaultMethod.java │ └── principle │ │ ├── Principle$Action.class │ │ ├── Principle.class │ │ └── Principle.java └── stream │ └── StreamTest.java ├── jcf ├── ArraysTest.java └── PerformanceTest.java ├── jmm ├── OOMMock.java ├── StackErrorMock.java └── StringOOMMock.java ├── keyworld ├── CheesyCounter.java ├── CloneStudy.java ├── VolatileStudy.java └── sync │ ├── StringThread.java │ └── SynchronizedStudy.java ├── load ├── A.java ├── SSClass.java ├── StaticTest.java ├── SubClass.java ├── SuperClass.java └── Test.java ├── lock ├── count │ ├── Counter.java │ ├── SharedVariableTest.java │ └── Test.java └── wait │ ├── DeadLock.java │ ├── Restaurant.java │ └── WaitTest.java ├── map ├── HashMapThread.java └── LinkedHashMapStudy.java ├── method_interface ├── BlockingQueueStudy.java ├── CallableAndFutureStudy.java ├── ClassLoaderStudy.java ├── DelayQueueStudy.java ├── MapStudy.java ├── NotifyStusy.java ├── ProxyStudy.java ├── ReflectStudy.java └── SerializeStudy.java ├── nio ├── FileChannelTest.java └── SocketChannelTest.java ├── oom ├── DirectMemoryOOM.java ├── HeapOOM.java ├── OOMObject.java ├── RuntimeConstantPoolOOM.java └── Test.java ├── proxy ├── Client.java ├── DynamicProxy.java ├── Subject.java └── SubjectImpl.java ├── sort └── QuickSort.java ├── stream └── StreamTest.java ├── task ├── FutureTaskTest.java └── RunnableFutureTaskTest.java ├── thread ├── InterruptTest.java ├── JoinDemo.java ├── JoinTest.java ├── ThreadLocalTest.java └── WaitTest.java ├── tree └── BinaryTreeStudy.java └── visibility └── VisibilityThred.java /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | .classpath 3 | .project 4 | .settings/ 5 | .externalToolBuilders 6 | /bin/ 7 | -------------------------------------------------------------------------------- /Chapter12 Java内存模型与线程.md: -------------------------------------------------------------------------------- 1 | # 深入理解Java虚拟机 # 2 | 3 | --- 4 | 5 | ## Chapter 12 Java内存模型与线程 ## 6 | 7 | ### 12.1 概述 ### 8 | 9 | > 10 | >**TPS**(Transcations Per Second),每秒事物处理数,是衡量一个服务器好坏的最重要指标之一。 11 | 12 | ### 12.2 硬件的效率与一致性 ### 13 | > 14 | >为了解决计算机数据存储速度与处理器计算速度之间相差好几个数量级的问题,现代计算机加入了**高速缓存(Cache)**作为内存与处理器之间的缓冲:将运算所需要的数据复制到缓存中,让运算能快速进行,当运算结束之后,再从缓存同步到内存中。 15 | > 16 | >新的问题:**缓存一致性(Cache Coherence)**。 17 | > 18 | >处理器、高速缓存、主内存之间的关系图: 19 | >![](img/Cache Coherence.jpg) 20 | 21 | ### 12.3 Java内存模型 ### 22 | > 23 | >**Java内存模型(Java Memory Model, JMM)** 24 | > 25 | >JMM的主要目标是:定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。 26 | 27 | #### 12.3.1 主内存与工作内存 #### 28 | >**主内存(Main Memory)**,JMM规定了所有的变量(包括了实例字段、静态字段和构成数组对象的元素,不包括局部变量和方法参数)都存储在主内存中(此处的主内存可以类比于Chapter12.2的主内存,但此处仅仅是虚拟机的一部分) 29 | > 30 | >**工作内存(Working Memory)**,每条线程独有,保存了该线程需要使用到的变量的主内存的副本拷贝,线程对变量的的所有操作都必须在工作内存中进行。 31 | > 32 | >线程、主内存、工作内存 三者的交互关系: 33 | >![](img/线程、主内存、工作内存之间的关系.png) 34 | 35 | #### 12.3.2 内存间交互操作 #### 36 | >关于内存与主内存之间具体的交互协议,JMM定义了以下八种操作来完成: 37 | > 38 | > - **lock(锁定)** :作用于主内存的变量,把一个变量标识为一条线程独占的状态。 39 | > 40 | > - **unlock(解锁)**:作用于主内存的变量,把处于锁定状态的变量释放出来,释放后的变量才能被其他线程锁定。 41 | > 42 | > - **read(读取)**:作用于主内存的变量,把一个变量的值从主内存传输到线程的工作内存中,以便随后的**load**动作使用。 43 | > 44 | > - **load(载入)**:作用于工作内存的变量,把**read**操作从主内存得到的变量值放入工作内存的变量副本中。 45 | > 46 | > - **use(使用)**:作用于工作内存的变量,把工作内存中的一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到的变量的值的字节码指令时,会使用到此操作。 47 | > 48 | > - **assign(赋值)**:作用于工作内存的变量,把一个从执行引擎接收到的值赋值给工作内存的变量,每当虚拟机遇到一个变量赋值的字节码指令时,会使用到此操作。 49 | > 50 | > - **store(存储)**:作用于工作内存的变量,把工作内存中一个变量的值传送到主内存中,以便以后的**write**操作使用。 51 | > 52 | > - **write(写入)**:作用于主内存的变量,把**store**操作从工作内存中得到的变量的值放入主内存的变量中。 53 | > 54 | > -------------------------------------------------------------------------------- /Chapter2 运行时数据区域.md: -------------------------------------------------------------------------------- 1 | # 深入理解Java虚拟机 # 2 | 3 | --- 4 | 5 | ## Chapter 2, Java内存区域、内存溢出异常 ## 6 | 7 | ### 2.1 概述 ### 8 | 9 | > Java与C++之间有一堵由**内存分配**和**垃圾收集**技术所围成的高墙,墙外的人想进来,墙里面的人想出来。 10 | 11 | ### 2.2 Java运行时数据区 ### 12 | 13 | > ![Java运行时数据区](img/Java runtime data area.png) 14 | 15 | #### 2.2.1 程序计数器 #### 16 | 17 | > **程序计数器(Program Counter Register)**是一块儿较小的空间,用来指示当前线程所执行字节码的行号。 18 | > 19 | > 字节码解释器工作时就是通过改变这个计数器的值来选定下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。 20 | > 21 | > *Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的*。在任一时刻,一个处理器(对于多核处理器来说,就是一个内核)只会执行一条线程中的指令。因此,为了能够恢复线程切换之前的线程状态到正确位置,每条线程都需要有一个独立的程序计数器,各条线程之间互不影响,独立存储,我们称这类内存区域为**“线程私有”**的内存。 22 | > 23 | > 如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行虚拟机字节码指令的地址;如果正在执行的是一个Native方法,这个计数器则是为空(Undefined)。 24 | > 此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。 25 | 26 | #### 2.2.2 虚拟机栈 #### 27 | 28 | > **Java虚拟机栈(Java Virtual Machine Stack)**也是线程私有的,它的生命周期与线程相同。它描述的是Java方法执行的内存模型:每个方法执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量、操作栈、动态链接、方法出口等信息。 29 | > *每一个方法被调用直至执行完成的过程,就对应着一个栈帧从虚拟机栈中从入栈到出栈的过程。* 30 | > 有人把Java内存区分为栈(Stack)和堆(Heap),这是比较粗糙的。实际上,这里的“栈”指的就是现在的这个虚拟机栈,或者确切点说,是虚拟机栈中的局部变量表部分。 31 | > 局部变量表中存放了编译期可知的基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(refrence类型,可能是一个对象起始地址的应用指针、也可能是一个代表对象的句柄或者其它与此对象相关的地址)和returnAddress(指向了一条字节码指令的地址)。 32 | > 其中,64位长度的long和double类型的数据会占用2个局部变量空间(Slot),其余数据类型会占用一个。局部变量所占用的空间在编译期间完成分配,当进入一个方法时,这个方法在帧中所需要分配的局部变量的空间时完全可以确定的,在运行期间也不会改变这个空间的大小。 33 | > 如果线程请求的栈的深度大于虚拟机所能允许的深度,会触发StackOverflowError异常;如果虚拟机可以动态地扩展(当前大部分虚拟机都可以扩展,也可以指定固定长度),当扩展无法申请到足够的内存时,会抛出OutOfMemoryError异常。 34 | 35 | #### 2.2.3 本地方法栈 #### 36 | 37 | > **本地方法栈(Native Method Stack)**与虚拟机栈的作用非常相似,只不过虚拟机栈是为虚拟机执行字节码(Java方法)服务,而本地方法栈是用来服务于虚拟机使用的Native方法服务。 38 | > 具体的虚拟机可以自由实现它,甚至可以把它和虚拟机栈合二为一(譬如Sun HotSpot 虚拟机)。 39 | > 与虚拟机栈一样,本地方法栈也会抛出StackOverflowError和OutOfMemoryErroe异常。 40 | 41 | #### 2.2.4 Java堆 #### 42 | 43 | > **Java堆(Java Heap)**是Java虚拟机所管理的内存中最大的一块。是被所有的线程共享的一块内存区域,在虚拟机启动时创建。 44 | > 45 | > 此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在此分配内存。由于JIT编译器的发展与逃逸分析技术的发展,栈上分配、标量替换优化技术的进步,所有的对象实例都分配在堆上也不是那么绝对了。 46 | > 47 | > *Java堆是垃圾收集器管理的主要区域*,因此也被称为“GC堆”(Garbage Collection Heap)。现在的收集器都是采用分代收集算法,所以Java堆中可以细分为:新生代和老生代。 48 | > 49 | > 根据Java虚拟机规范,Java堆可以是处于物理上不连续的内存空间中,只要逻辑上连续即可。在实现上可以是固定大小,也可以是可扩展的,主流的是可扩展方式。 50 | 51 | ### 2.2.5 方法区 ### 52 | 53 | > **方法区(Method Area)**与Java堆一样,都是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态常量、即时编译器编译后的代码等数据。 54 | > 55 | > Java虚拟机规范对这个区域的限制非常松,除了和Java堆一样不需要连续的内存空间和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集。 56 | > 57 | > 当方法区的内存大小无法满足内存分配需要的时候,将抛出OutOfMemory异常。 58 | 59 | ### 2.2.6 运行时常量池 ### 60 | 61 | > **运行时常量池(Runtime Constant Pool)**是方法区的一部分。Class文件除了有类的版本、字段、方法、接口等描述信息,还有一项信息就是常量池,用于存放编译时期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池。 62 | > 63 | > 运行时常量池相对于Class文件常量池的另外一个重要特征是**具备动态性**,Java语言并不要求常量一定只能在编译期产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将将新的常量放入池中,这种特性被开发人员利用的比较多的便是String类的intern()方法。 64 | > 65 | > 既然运行时常量池是方法区的一部分,自然会受到方法区内存的限制,当常量池无法再申请到内存时将会抛出OutOfMemoryError异常。 66 | 67 | ### 2.2.7 直接内存 ### 68 | 69 | > **直接内存(Direct Memory)**并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且有可能导致OutOfMemoryError异常。 70 | > 71 | > 在JDK1.4种新加入了NIO(New Iuput/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这快内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。 72 | > 73 | > 显然,本机直接内存非分配不会受到Java堆大小的限制,但是既然是内存,肯定会受到本机总内存的大小和处理器寻址空间的限制。所以也可能会抛出OutOfMemoryError异常。 74 | 75 | ### 2.3 对象访问 ### 76 | 77 | > 对象访问在Java语言中无处不在,是最普通的程序行为,即使是最简单的访问,也涉及到Java栈、Java堆、方法区这三个重要的内存区域之间的关联关系,如下一句代码: 78 | > 79 | > ```Object obj = new Object();``` 80 | > 81 | > 假设这句代码出现在方法体中,那"Object obj"这部分的语义将会反映到Java栈的本地变量中,作为一个Reference类型数据出现。 82 | > 83 | > 而"new Object()"这部分的语义将会反映到Java堆中,形成一块儿存储了Object类型所有实例数据值(Instance Data,对象中各个实例字段的数据)的结构化内存,根据具体类型以及虚拟机实现的对象内存布局(Object Memory Layout)的不同,这块儿内存的大小是不固定的。 84 | > 85 | > 另外,在Java堆中,还必须包含能包括能查到此对象类型数据(如,对象类型、父类、实现的接口、方法等)的地址信息,这些数据存储在方法区中。 86 | > 87 | > 由于reference类型在Java虚拟机规范里只规定了一个指向对象的引用,并没有定义这个引用应该通过哪种方式去定位,以及访问到Java堆中的对象的具体位置,因此不同的虚拟机实现的对象访问方式会有所不同。 88 | > 89 | > 主流的访问方式有两种:使用句柄和直接指针。 90 | > 91 | - **句柄方式**,Java堆中将会划分出一块内存作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息,如下图: 92 | 93 | > ![句柄方式访问对象](img/access object by handle.jpg) 94 | > 95 | - **指针方式**,reference变量中直接存储的就是对象的地址,而Java堆对象的布局中就必须考虑如何防止访问类型数据的相关信息,如下图: 96 | 97 | > ![指针方式访问对象](img/access object by pointer.jpg) 98 | 99 | > 这两种对象的访问方式各有优势: 100 | > 101 | - 使用句柄访问方式的最大好处是reference中存贮的是稳定的句柄地址,在对象被移动(比如垃圾收集时,对象移动是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要被修改。 102 | - 使用直接指针访问方式的最大好处就是速度更快,它节省了一次指针定位的时间开销,由于对象的访问在Java中非常频繁,因此这类开销积少成多也是一项非常可观的执行成本。 103 | - *本书讨论的主要虚拟机Sun HotSpot,它是使用第二种方式进行对象访问的,但是从整个软件开发的范围来看,各种语言和框架使用句柄来访问的情况也十分常见。* 104 | 105 | ## 2.4 实战:OutOfMemoryError异常 ## 106 | ### 2.4.1 Java堆溢出 ### 107 | > 可以通过限制Java堆的大小,设置为不可扩展(将堆的最小值参数-Xms和最大值参数-Xmx设置成一样即可避免堆自动扩展),通过参数-XX:+HeapDumpOnOutOfMemoryError可以让虚拟机在出现内存溢出异常时Dump出当前的内存堆转储快照以便以后进行分析。 108 | > Java堆内存的OOM异常是实际应用中最常见的内存溢出异常情况。出现Java堆内存溢出时,异常堆栈信息“java.lang.OutOfMemoryError”会跟着进一步提示“Java heap space”。如下图所示: 109 | > ![OOM](img/oom.png) 110 | > 要解决这个区域的异常,一般的手段是首先通过内存映像分析工具(如Eclipse Memory Analyzer)对dump出的堆转储快照进行分析,重点是确认内存中的对象是否是必要的,也就是要先分清楚到底是出现了内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。如下图展示了使用Eclipse Memory Analyzer Tools打开的堆转储快照文件: 111 | > ![Eclipse Memory Analyzer Tools](img/mat.png) 112 | > 如果是内存泄漏,可进一步通过工具查看泄漏对象到GC Roots的引用链。于是就能找到泄漏对象是通过怎样的路径与GC Roots相关联并导致垃圾收集器无法自动回收它们的。掌握了泄漏对象的类型信息,以及GC Roots引用链的信息,就可以比较准确地定位出泄漏代码的位置。 113 | > 如果不存在泄漏,换句话说就是内存中的对象确实都还必须存活着,那就应当检查虚拟机的堆参数(Xmx和Xms),与机器物理内存对比看是否还可以调大,从代码上检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期间的内存消耗。 114 | 115 | ### 2.4.2 虚拟机栈和本地方法栈溢出 ### 116 | > 由于在HotSpot虚拟机中并不区分虚拟机栈和本地方法栈,因此对于HotSpot来说,-Xoss参数(设置本地方法栈大小)虽然存在,但实际上是无效的,栈容量只由-Xss参数设定。 117 | > 关于虚拟机栈和本地方法栈,在Java虚拟机规范中描述了两种异常: 118 | > 119 | - 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。 120 | > 121 | - 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。 122 | 123 | > 这里把异常分为两种情况,实际上却存在着一些互相重叠的地方:当栈空间无法分配时,到底是内存太小,还是已使用的栈空间太大,其本质只是对同一事件的两种表述而已。 124 | 125 | ### 2.4.3 运行时常量池溢出 ### 126 | > 如果要向运行时常量池中添加内容,最简单的方法是使用String.intern()这个Native方法。该方法的作用时:如果池中包含了一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。由于常量池分配在方法区内,我们可以通过-XX:PermSize和-XX:MaxPermSize限制方法区的大小,从而间接限制其中常量池的容量。 127 | 128 | ### 2.4.4 方法区溢出 ### 129 | > 方法区用于存放Class相关的信息,如类名、访问修饰符、常量池、字段描述、方法描述等。生成大量的动态类区填充方法区,可以触发此区域的溢出异常。 130 | > 方法区溢出是一种常见的内存溢出异常,一个类如果要被垃圾收集器回收,判定的条件比较苛刻。在经常动态生成大量Class的应用中,需要特别注意类的回收状况。这类场景出了CGLib字节码增强外,还有大量JSP或者基于OSGi的应用等。 131 | 132 | ### 2.4.5 本机直接内存溢出 ### 133 | > DirectMemory可以通过-XX:MaxDirectMemorySize指定,如果不指定,则默认与Java堆的最大值(-Xmx指定)一样。 134 | -------------------------------------------------------------------------------- /Chapter3 垃圾收集器与内存分配策略.md: -------------------------------------------------------------------------------- 1 | # 深入理解Java虚拟机 # 2 | 3 | --- 4 | 5 | ## Chapter 3, 垃圾收集器与内存分配策略 ## 6 | 7 | ### 3.1 概述 ### 8 | 9 | > 垃圾收集(Garbage Collection , GC)的历史远远比Java久远。它需要完成三件事: 10 | > 11 | - 哪些内存需要回收 12 | - 什么时候回收 13 | - 如何回收 14 | 15 | > 程序计数器、虚拟机栈、本地方法栈三个区域随线程而生,随线程而灭;栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作,每一个栈帧需要分配多少内存基本上是在类结构确定下来时就已知的(尽管在运行期会由JIT编译器进行一些优化,但是大体上可以认为是编译器可知的),因此在这几个区域的内存分配和回收都具有确定性,这几个区域不太需要过多地考虑回收的问题。而Java堆和方法区则不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序处于运行期间才能知道会创建哪些对象,这部分的内存分配和回收都是动态的,垃圾收集器需要关注的是这部分内存,我们所讨论的“内存”分配与回收也仅仅指着一部分。 16 | 17 | ### 3.2 对象已死? ### 18 | > 堆中存放着Java世界中几乎所有的对象,垃圾收集器在对堆进行回收前,第一件事就是要确定哪些对象还“存活着”,哪些已经“死去”(即不可能再被任何途径使用的对象)。 19 | 20 | #### 3.2.1 引用计数算法 #### 21 | > **引用计数算法(Reference Counting)**:给对象添加一个引用计数器,每当有一个地方引用它时,计数器的数值就加1;当引用失效时,计数器数值就减1;任何时刻计数器都为0的对象就是不可能再被使用的。 22 | > 实际上,Java并没有采用引用计数算法,因为它很难解决对象之间的相互循环引用的问题。 23 | 24 | #### 3.2.2 根搜索算法 #### 25 | > 在主流的商业程序语言中(Java和C#),都是使用**根搜索算法(GC Roots Tracing)**来判定对象是否存活的。 26 | > 这个算法的基本思路是:通过一系列的名字为“GC Roots”的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为**引用链(Reference Chain)**,当一个对象到GC Roots没有任何引用链对象相连(用图论的话说,就是从GC Roots到这个对象不可到达)时,则证明此对象不可用。 27 | > 如下图示: 28 | > 29 | > ![GC Roots Tracing](img/GC Root Tracing.jpg) 30 | > 31 | > - 对象object5、object6和object7虽然互相关联,但是他们到GC Roots是不可到达的,所以它们会被判定为师可回收对象。 32 | > 在Java中,可以作为GC Roots的对象有以下几种: 33 | > 34 | > - 虚拟机栈(栈中的本地变量表)中的引用的对象 35 | > - 方法区中的类静态属性引用的对象 36 | > - 方法区中的常量引用的对象 37 | > - 本地方法栈中JNI(即一般说的Native方法)的引用的对象 38 | 39 | #### 3.2.3 再谈引用 #### 40 | > 在JDK1.2之前,Java中的引用(Reference)非常狭隘: 41 | > 42 | > **如果Reference类型的数据中存储的数值代表着另一块内存的起始地址,就称这块内存代表着一个引用。** 43 | > 44 | > 在JDK1.2之后,Java对引用的概念进行了扩充,将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)。这四种引用强度依次减弱。 45 | > 46 | > - **强引用**,就是在程序代码中普遍存在的,类似```Object obj = new Object()```这类的引用,只要强引用还存在,垃圾回收器永远不会回收掉被引用的对象。 47 | > - **软引用**,用来描述一些还有用,但是并非必需的对象。对于软引用关联的对象,在系统将要发生内存溢出异常之前,将会把这些对象放进回收范围之中并进行第二次的回收。如果这次回收还是没有足够的内存,才会抛出内存溢出异常。在JDK1.2之后,提供了SoftReference类来实现软引用。 48 | > - **弱引用**,也是用来描述非必需对象的,但是它的强度要比软引用弱一些,被弱引用关联的对象只能生存到下一次垃圾回收之前。当垃圾回收器工作时,不论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK1.2之后,提供了WeakReference来实现弱引用。 49 | > - **虚引用**,也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不影响其生存时间,也无法通过虚引用来获取一个对象的实例。为一个对象设置虚引用的唯一目的就是希望这个对象被收集器回收时收到一个系统通知。在JDK1.2之后,提供了PhantomReference类来实现虚引用。 50 | 51 | #### 3.2.4 生存还是死亡? #### 52 | > 在根搜索算法不可达的对象,也并非是“非死不可”的,它们暂时处于“死缓”状态,要真正宣告对象的死亡,至少要经历两次标记: 53 | > 54 | > 如果对象在进行根搜索后发现没有与GC Roots相连接的引用链,那它就会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。 55 | > 56 | > 如果这个对象被判定为有必要执行**finalize()方法**,那么这个对象就会被放在名为F-Queue的队列中,并在稍后有一条由虚拟机自动建立的、低优先级的Finalizer线程去执行。这里所说的“执行”是指虚拟机会触发这个方法,但是并不承诺会保证等待它运行结束。(这样做的目的是,如果一个对象在finalize()方法中执行缓慢或者是发生了死循环,将可能会导致F-Queue里的其他对象永久处于等待状态,甚至导致整个内存回收系统崩溃)。 57 | > 58 | > finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模标记,如果对象要在finalize()方法中成功拯救自己,只要重新与引用链上的任何对象建立关联即可,譬如把自己(this关键字)复制给某个类变量或者对象的成员变量。 59 | 60 | #### 3.2.5 回收方法区 #### 61 | > Java虚拟机规范不要求虚拟机在方法区实现垃圾收集,而且在方法区进行垃圾收集的“性价比”一般都比较低:在堆中,尤其是在新生代中,常规应用进行一次垃圾收集一般可回收70%~95%的空间,而永久代的垃圾收集效率远低于此。 62 | > 63 | > 永久代的垃圾收集主要分为两部分内容:废弃常量和无用的类。 64 | > 65 | > **回收废弃常量**与回收Java堆中的对象非常类似,假如一个字符串“abc”已经进入常量池,但是当前系统没有任何一个String对象是叫做“abc”的,换句话说就是没有任何对象引用常量池的“abc”常量,也没有其他地方引用了这个字面量,如果这时候发生内存回收,而且有必要的话,这个“abc”就会被系统“请”出常量池。常量池中的其他类(接口)、方法、字段的符号引用也与此类似。 66 | > 67 | > 类需要同时满足以下三个条件,才能算是**“无用的”类**: 68 | > 69 | > - 该类所有的实例都被回收,也就是说Java堆中已经不存在该类的所有实例。 70 | > - 加载该类的ClassLoader已经被回收 71 | > - 该类对应的 ```java.lang.class``` 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法 72 | > 73 | > 虚拟机在一个类同时满足以上三个条件时,**可以**对这个无用类进行回收。(⚠️,这里说的仅仅是“**可以**”,而不是和对象一样,不使用了就必然会回收)。HotSpot虚拟机提供了 ```-Xnoclassgc``` 参数来进行控制,还可以使用 ```-verbose:class``` , ```-XX:+TraceClassLoading``` , ```-XX:+TraceClassUnLoading``` 查看类的加载和卸载信息。 74 | > 75 | > 在大量使用反射、动态代理、CGLib等bytecode框架的场景,以及动态生成JSP和OSGi这类频繁自定义ClassLoader的场景都需要虚拟机具备类卸载的功能,以保证永久代不会溢出。 76 | 77 | ### 3.3 垃圾收集算法 ### 78 | > 垃圾收集算法涉及到大量的程序细节,而且各个平台的虚拟机操作内存的方法又各不相同,因此本节着重介绍几种算法的思想和发展过程。 79 | 80 | #### 3.3.1 标记-清除算法 #### 81 | > **标记-清除(Mark-Sweep)算法**,分为两个部分**标记**和**清除**,首先标记出所有需要回收的对象,在标记完成之后统一回收掉所有被标记的对象。 82 | > 83 | > 它是最基础的算法,是因为后续的算法都是基于这种思路并对其缺点进行改进而得到的。 84 | > 85 | > 它的主要缺点有两个: 86 | > 1, 效率问题,标记或清除过程的效率都不高; 87 | > 2, 空间问题,标记清除之后会产生大量的不连续的空间碎片,在以后需要分配大对象时无法找到足够的连续内存空间而不得不进行一次另一次垃圾清理。 88 | 89 | ### 3.3.2 复制算法 ### 90 | > **复制(Copying)算法**的出现是为了解决“标记-清除算法”的效率问题,它将可用内存按照容量划分为大小相等的两块,每次只使用其中一块。当这一块内存使用完了,就将还存活着对象复制到另外一块上面,然后再将已使用过的内存空间一次清理掉。这样就使得每一次都是对其中一块进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只需要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。 91 | > 92 | > 现在的商业虚拟机都采用这种收集算法来回收新生代,新生代中的对象绝大部分都是朝生夕死的,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块较大的Eden空间和两块较小的Survivor,每次使用Eden和其中一块Survivor,当回收时,将Eden和Survivor中存活的对象一次性地拷贝到另一块Survivor空间,最后清理掉Eden和Survivor空间。 93 | > 94 | > HotSpot虚拟机默认的Eden和Survivor大小比例为8:1,也就是说每次新生代中可用空间为整个新生代空间的90%(80%+10%),只有10%的内存空间是被“浪费”的。当Survivor的空间不够用的时候,需要依赖其他内存(老年代)进行**分配担保(Handle Promotion)**。 95 | 96 | ### 3.3.3 标记-整理算法 ### 97 | > **标记-整理(Mark-Compact)算法**:标记过程与“标记-清除”算法一样,但是后续步骤不是直接对可回收对象进行清理,而是让所有的存活对象都向一端移动,然后直接清理掉端边界以外的内存。 98 | 99 | ### 3.3.4 分代收集算法 ### 100 | > 当前商业虚拟机的垃圾收集都是采用**“分代收集(Generational Collection)算法”**,根据对象的存活周期的不同将内存划分为几块。 101 | > 102 | > 一般是把Java堆分为**新生代**和**老年代**,这样就可以根据各个年代的特定采用最适当的收集算法。在新生代,每次垃圾收集都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成省收集。而老年代中因为对象存活率高,没有额外的空间进行分配担保,就必须使用“标记-清理”或者“标记-整理”算法来进行回收。 103 | 104 | ## 3.4 垃圾收集器 ## 105 | > 垃圾收集器是内存回收的具体实现,Java虚拟机规范对垃圾收集器的实现并没有具体规定,因此不同厂商、不同版本的虚拟机所提供的垃圾收集器可能会有很大的区别。 106 | > 以下是 HotSpot JVM 1.6 的垃圾收集器: 107 | > ![HotSpot JVM 1.6 GC ](img/HotSpot JVM 1.6 GC .jpg) 108 | > 109 | > 其中,如果两个收集器之间有连线,说明可以搭配使用。 110 | 111 | ### 3.4.1 Serial 收集器 ### 112 | > 特点: 113 | > 114 | > - 单线程收集器 115 | > - 在进行垃圾收集时,必需暂停其他所有的工作线程(打扫卫生时,必需要求房间里停止工作产生垃圾) 116 | > - 简单而高效,专心做垃圾收集 117 | > - 虚拟机运行在Client模式下的默认新生代收集器 118 | 119 | ### 3.4.2 ParNew 收集器 ### 120 | > ParNew收集器其实就是Serial收集器的多线程版本,是运行在Server模式下的虚拟机中首选的新生代收集器。 121 | > 122 | > *并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程处于等待状态。* 123 | > 124 | > *并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替运行),用户程序继续运行,而垃圾收集线程运行在另一个CPU上。* 125 | 126 | ### 3.4.3 Parallel Scavenge ### 127 | > Parallel Scavenge收集器是一个使用复制算法的并行的多线程收集器,它关注于提高吞吐量(Throughput,CPU用于运行用户代码的时间和CPU消耗时间的比值)。另外,自适应调节策略也是Parallel Scavenge和ParNew收集器的区别 128 | 129 | ### 3.4.4 Serial Old 收集器 ### 130 | > 是Serial收集器的老年版本。 131 | 132 | ### 3.4.5 Parallel Old 收集器 ### 133 | > 是Parallel Scavenge 收集器的老年版本。 134 | 135 | ### 3.4.6 CMS 收集器 ### 136 | > CMS(Concurrent Mask Sweep)收集器是一个以获取最短回收停顿时间为目标的收集器。因此,此收集器特别适合现代的互联网或 B/S 架构的服务端上。 137 | 138 | > CMS 收集器是基于“标记-清除”算法实现的,整个过程分为4个步骤: 139 | 140 | > - 初始标记 141 | > - 并发标记 142 | > - 重新标记 143 | > - 并发清除 144 | > 145 | > 它是一种优秀的收集器。 146 | 147 | > - 优点是:并发收集、低停顿 148 | > - 缺点是:对CPU资源非常敏感、无法处理浮动垃圾、收集结束后会产生大量的空间碎片以致于在给大对象分配空间时带来麻烦 149 | 150 | ### 3.4.7 G1 收集器 ### 151 | > G1(Garbage First)收集器是当前收集器技术发展的最新成果,相对于上文的 CMS 收集器有两个显著改进: 152 | 153 | > 154 | 1. 基于“标记-整理”算法,也就是说它不会产生空间碎片 155 | 2. 非常精确地控制停顿 156 | 157 | > G1 收集器可以实现在基本不牺牲吞吐量的情况下完成低停顿的回收,它将整个Java堆划分为多个大小固定的独立区域(Region),并跟踪这些区域里面的垃圾堆积程度,在后台维护一个优先列表,每次根据允许的收集时间,优先回收垃圾最多的区域(这也是Garbage First名称的由来)。总而言之,区域划分和有优先级的区域回收,保证了G1收集器在有限的时间内可以获得最高的收集效率。 158 | 159 | ### 3.4.8 垃圾收集器参数总结 ### 160 | > 161 | -XX:+UseSerialGC:在新生代和老年代使用串行收集器 162 | -XX:SurvivorRatio:设置eden区大小和survivior区大小的比例 163 | -XX:NewRatio:新生代和老年代的比 164 | -XX:+UseParNewGC:在新生代使用并行收集器 165 | -XX:+UseParallelGC :新生代使用并行回收收集器 166 | -XX:+UseParallelOldGC:老年代使用并行回收收集器 167 | -XX:ParallelGCThreads:设置用于垃圾回收的线程数 168 | -XX:+UseConcMarkSweepGC:新生代使用并行收集器,老年代使用CMS+串行收集器 169 | -XX:ParallelCMSThreads:设定CMS的线程数量 170 | -XX:CMSInitiatingOccupancyFraction:设置CMS收集器在老年代空间被使用多少后触发 171 | -XX:+UseCMSCompactAtFullCollection:设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片的整理 172 | -XX:CMSFullGCsBeforeCompaction:设定进行多少次CMS垃圾回收后,进行一次内存压缩 173 | -XX:+CMSClassUnloadingEnabled:允许对类元数据进行回收 174 | -XX:CMSInitiatingPermOccupancyFraction:当永久区占用率达到这一百分比时,启动CMS回收 175 | -XX:UseCMSInitiatingOccupancyOnly:表示只在到达阀值的时候,才进行CMS回收 176 | 177 | ## 3.5 内存分配与回收策略 ## 178 | > Java 技术体系中的自动内存管理最终可以可以归结为自动化地解决了以下两个问题:**给对象分配内存**和**回收分配给对象的内存**。 179 | > 180 | > 其中,关于**回收内存**是上文介绍的虚拟机中垃圾收集体系及其工作原理所阐述的内容。 181 | > 182 | > 而,关于**分配内存**则是本节需要阐述的内容。 183 | 184 | ### 3.5.1 对象优先在Eden分配 ### 185 | > 大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够的空间进行分配时,虚拟机将发起一次Minor GC。 186 | > 187 | > - **新生代GC(Minor GC)**:指发生在新生代的垃圾收集动作,因为Java对象大多数都具有朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也比较快。 188 | > - **老年代GC(Major GC/Full GC)**:指发生在老年代的GC,出现了Major GC,经常会伴随至少发生一次的Minor GC(但是并非绝对,在ParallelScavenge收集器的收集策略里,就有直接进行Major GC的策略选择过程)。Major GC的速度一般会比Minor GC慢10倍以上。 189 | 190 | ### 3.5.2 大对象直接进入老年代 ### 191 | > 大对象,是指需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串及数组。大对象对于虚拟机的内存分配来说,是一个坏消息,因为它的经常出现容易导致内存还有不少空间时就提前触发垃圾收集以获取足够的连续空间来“安置”它们。 192 | > 193 | > 虚拟机提供了```-XX:PretenureSizeThreshold```参数,让大于这个设置值的对象直接在老年代中分配,这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法来收集内存)。 194 | > 195 | > *PretenureSizeThreshold参数只对Serial和ParNew两款收集器有效,Parallel Scavenge收集器不认识这个参数,一般也没必要设置。如果遇到必需使用此参数的场合,可以考虑ParNew+CMS的收集器组合* 196 | 197 | ### 3.5.3 长期存活的对象进入老年代 ### 198 | > 虚拟机采用了分代收集的思想来管理内存,那么回收时就必须能够识别哪些对象应当放在新生代,哪些对象应该放在老年代。为了达到这个目的,虚拟机给每个对象定义了一个对象年龄(Age)计数器。 199 | > 200 | > 如果对象在Eden出现并经过第一次MinorGC后仍然存活,并且能被Survivor容纳,将被移动到Survivor空间,对象年龄加1。对象在Survivor区每熬过一次Minor GC,年龄就增加1岁,当它的年龄增加到一定程度(默认值是15)时,就会被晋升到老年代中。 201 | > 202 | > *对象晋升老年代的年龄阈值,可以通过参数```-XX:MaxTenuringThreshold```来设置* 203 | 204 | ### 3.5.4 动态对象年龄判定 ### 205 | > 为了能够更好地适应不同程序的内存状况,虚拟机并不是总要求对象的年龄必需达到MaxTenuringThreshold 才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold 中要求的年龄。 206 | 207 | ### 3.5.5 空间分配担保 ### 208 | > 在发生Minor GC时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小,如果大于,则改为直接进行一次Full GC。如果小于,则查看HandlePromotionFailure设置是否允许担保失败;如果允许,那只会进行Minor GC;如果不允许,则也要改为进行一次Full GC。 209 | 210 | -------------------------------------------------------------------------------- /Chapter4 虚拟机性能监控与故障处理工具.md: -------------------------------------------------------------------------------- 1 | # 深入理解Java虚拟机 # 2 | 3 | --- 4 | 5 | ## Chapter 4 虚拟机性能监控与故障处理工具 ## 6 | 7 | ### 4.1 概述 ### 8 | 9 | > 给一个系统定位问题时,知识、经验是关键基础,数据是依据,工具是运用知识处理数据的手段。 10 | 11 | ### 4.2 JDK命令行工具 ### 12 | > -------------------------------------------------------------------------------- /Chapter6 类文件结构.md: -------------------------------------------------------------------------------- 1 | # 深入理解Java虚拟机 # 2 | 3 | --- 4 | 5 | ## Chapter 6 类文件结构 ## 6 | 7 | ### 6.1 概述 ### 8 | 9 | > 现在越来越多的程序语言选择了与操作系统无关和机器指令无关的、平台中立的格式作为程序编译后的存储格式。 10 | 11 | ### 6.2 无关性的基石 ### 12 | > ![Java虚拟机提供的语言无关性](img/Java虚拟机提供的语言无关性.png) 13 | 14 | ### 6.3 Class类文件的结构 ### 15 | > Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在Class文件中,中间没有添加任何分隔符。当遇到需要占用8位字节以上空间的数据项时,则会按照高位在前的方式分割成若干个8位字节进行存储。 16 | > 17 | > 按照Java虚拟机规范,Class文件格式采用一种类似于C语言结构体的伪结构来存储,这种结构中只有两种数据类型:无符号数和表。 18 | > 19 | > - **无符号数**属于基本的数据类型,以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节、和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值、或者按照UTF-8编码构成字符串值。 20 | > - **表**是由多个无符号数或其他表作为数据项构成的复合数据类型,所有的表都习惯性地以```"_info"```结尾。表用于描述有层次关系的复合数据结构的数据,整个Class文件本质上就是一张表,它由如下所示的数据项构成: 21 | > ![Class文件格式](img/Class文件格式.jpg) 22 | > 23 | > 无论是无符号数还是表,当需要描述同一类型单数量不定的多个数据时,经常会使用一个前置的容量计数器加若干个连续的数据项的形式,这时候称这一系列连续的某一类型的数据位某一类型的集合。 24 | 25 | #### 6.3.1 魔数与Class文件的版本 #### 26 | > 每个Class文件的头4个字节称为魔数(Magic Number),它的唯一作用时用语确定这个文件是否作为一个能被虚拟机接受的Class文件。Class文件的魔数值是```0xCAFEBABE```(咖啡宝贝?)。 27 | > 28 | > 紧挨着魔数的4个字节存储的是Class文件的版本号:第5和6个字节是次版本号(Minor Version),第7和8个字节是主版本号(Major Version)。Java的版本号是从45开始的,以后每个大版本发布后,主版本号向上加1,高版本的JDK能向下兼容以前版本的Class文件,但不能运行以后版本的Class文件,即使文件格式并未发生变化。 29 | 30 | #### 6.3.2 常量池 #### 31 | > 紧接着主次版本号之后的是常量池入口,它是Class文件中与其它项目关联最紧密的数据类型,也是占用Class文件空间最大的数据项目之一,同时还是Class文件中第一个出现的表类型数据项目。 32 | > 33 | > 常量池中主要存放两大类常量:字面量(Literal)和符号引用(Symbolic Reference)。字面量比较接近Java语言的常量概念,如文本字符串、被声明为final的常量值等。而符号引用则属于编译原理方面的概念,包括了下面三类常量: 34 | > 35 | > - 类和接口的全限定名(Fully Quaified Name) 36 | > - 字段的名称和描述 37 | > - 方法的名称和描述符 38 | 39 | #### 6.3.3 访问标志 #### 40 | > **访问标志(access_flag)**:用于识别一些类或接口层次的访问信息,包括:这个Class是类还是接口,是否定义为public类型,是否定义为abstract类型,如果是类的话,是否被声明为final,等等。 41 | > 42 | > 具体的标志位及含义,见下表: 43 | > 44 | > ![Class文件的访问标志](img/Class文件的访问标志.jpg) 45 | 46 | #### 6.3.4 类索引、父类索引、接口索引集合 #### 47 | > 类索引(this_class)和父类索引(super_class)都是一个u2类型的数据,而接口索引集合是一个u2类型的数据集合,class文件由这三个数据来确定这个类的继承关系。 48 | 49 | #### 6.3.5 字段表集合 #### 50 | > **字段表(field_info)**:用于描述类或者接口的声明的变量,不包括方法的内部声明变量。 51 | > 52 | > Java中一个字段(field)可以包含的信息包括:字段的作用域(public、private、protected)、类级别还是实例级别(static)、可变性(final)、并发可见性(volatile是否强制从主内存读写)、可否序列化(transient)、字段数据类型(基本类型、对象、数组)、名称。 53 | 54 | #### 6.3.6 方法表集合 #### 55 | > 方法表的结构如同 【Chapter 6.3.5 字段表集合】一样,一次包括了,访问标识(access_flag)、名称索引(name_index)、描述符索引(descriptor_index)、属性表集合(attributes)。 56 | 57 | #### 6.3.7 属性表集合 #### 58 | > **属性表集合(attribute_info)**:用于描述某些场景(Class文件、字段表、方法表)的专有信息。 59 | 60 | ##### 6.3.7.1 Code属性 ##### 61 | > Java程序方法体里面的代码经过javac编译器处理之后,最终会变成字节码指令存储在Code属性内。 62 | 63 | ##### 6.3.7.2 Exceptions属性 ##### 64 | > 列举出方法体中可能抛出的受查异常(checked exception),也就是方法描述时在throws关键字后面的异常。 65 | 66 | ##### 6.3.7.3 LineNumberTable属性 ##### 67 | > 用于描述Java字节码行号与源代码行号之间的对应关系(字节码的偏移量)。 68 | 69 | ##### 6.3.7.4 LocalVariableTable属性 ##### 70 | > 用于描述栈帧中局部变量表中的变量和Java源代码中定义的变量之间的关系。 71 | 72 | ##### 6.3.7.5 SourceFile属性 ##### 73 | > 用于记录生成这个Class文件的源码文件的名称。 74 | 75 | ##### 6.3.7.6 ConstantValue属性 ##### 76 | > 通知虚拟机自动为静态变量赋值。 77 | 78 | ##### 6.3.7.7 InnerClasses属性 ##### 79 | > 用于记录内部类与宿主之间的关联。 80 | 81 | ##### 6.3.7.8 Deprecated和Synthetic属性 ##### 82 | > Deprecated属性用于表示某个类、字段或者方法,已经被程序作者定位废弃不推荐使用,可以在代码中通过 ```@deprecated``` 注释来设置。 83 | 84 | > Synthetic属性代表字段或方法并不是由Java源代码直接产生的,而是由编译器自行添加的。 85 | 86 | ### 6.4 Class文件的发展 ### 87 | > 略 88 | 89 | *EOF* -------------------------------------------------------------------------------- /Chapter7 虚拟机类加载机制.md: -------------------------------------------------------------------------------- 1 | # 深入理解Java虚拟机 # 2 | 3 | --- 4 | 5 | ## Chapter 7 虚拟机类的加载机制 ## 6 | 7 | ### 7.1 概述 ### 8 | 9 | > 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是**虚拟机的类的加载机制**。 10 | 11 | ### 7.2 类的加载时机 ### 12 | > ![类的生命周期](img/类的生命周期.jpg) 13 | > 14 | > - **加载(Loading)**:按照虚拟机规范,**有且只有**以下四种情况下必须立即对类进行“初始化”: 15 | > - 遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有初始化,则需要先出发其初始化。生成这4条指令的典型场景是:使用 ```new``` 关键字实例化对象的时候、读取或设置一个类的静态字段的时候(被final修饰、已在编译期把结果放入常量池的静态字段除外)、以及调用一个类的静态方法的时候 16 | > - 使用 ```java.lang.reflect``` 包的方法对类进行反射调用的时候 17 | > - 当初始化一个类时,如果发现它的父类还没有进行初始化,则需要先触发其父类进行初始化 18 | > - 当虚拟机启动时,用户需要指定一个要执行的主类(包含main方法的类),虚拟机会先初始化这个类 19 | 20 | ### 7.3 类的加载过程 ### 21 | > 加载、验证、准备、解析、初始化 22 | #### 7.3.1 加载 ### 23 | > **加载(Loading)**阶段,虚拟机需要完成以下三件事: 24 | 25 | > - 通过一个类的全限定名来获取定义这个类对应的二进制字节流 26 | > - 将这个类的二进制字节流所代表的静态存储结构转换为方法区的运行时数据结构 27 | > - 在Java堆中生成一个代表这个类的 ```java.lang.Class``` 对象,作为方法区这些数据的访问入口。 28 | 29 | ### 7.3.2 验证 ### 30 | > 验证是虚拟机对自身保护的一项重要工作。 31 | > 32 | > 大致完成以下四个阶段的检验过程: 33 | > 34 | > - **文件格式验证**,验证字节流是否符合Class文件格式规范,并且能被当前版本的虚拟机处理。 35 | > - **元数据验证**,对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言规范要求。 36 | > - **字节码验证**,主要工作是进行数据流和控制流分析,保证被校验类的方法不会危害到虚拟机的安全。 37 | > - **符号引用验证**,可以看作是对类自身以外(常量池中的各种符号引用)的信息进行匹配性的校验。 38 | 39 | ### 7.3.3 准备 ### 40 | > 准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配。 41 | 42 | ### 7.3.4 解析 ### 43 | > 是虚拟机将常量池中的符号引用替换为直接引用的过程。 44 | > 45 | > 解析动作主要针对类或接口、字段、类方法、接口方法四类符号引用分别进行。 46 | 47 | ### 7.3.5 初始化 ### 48 | > 真正开始执行类中定义的Java程序代码(或者说是字节码)。 49 | 50 | ## 7.4 类加载器 ## 51 | > 类加载过程中的*“通过一个类的全限定名来获取描述这个类的二进制字节流”*这个动作是放在Java虚拟机的外部来实现的,以便于让应用程序自己来决定如何去获取所需要的类,实现这个动作的代码模块被称为**“类加载器”**。 52 | 53 | ### 7.4.1 类和类加载器 ### 54 | > **类加载器**虽然只用于实现类的加载动作,但是它的作用却远远不限于此,比较两个类是否“相等”,不仅仅要确认这两个类是否来源于同一个class文件,还需要加载这两个类的类加载器相同。 55 | ### 7.4.2 双亲委派模型 ### 56 | > 站在虚拟机的角度,只存在两种类加载器: 57 | > 58 | > - **启动类加载器(Bootstrap ClassLoader)**,使用C++实现,是虚拟机的一部分 59 | > - 其他类加载器,由Java语言实现,独立于虚拟机之外的,全部继承自抽象类 ```java.lang.ClassLoader``` 60 | > 61 | > 从开发人员的角度,类加载器可以划分得更细致一些: 62 | > 63 | - **启动类加载器(Bootstrap ClassLoader)**:负责将存放在 ```\lib``` 目录中的,或者被 ```-Xbootclasspath``` 参数所指定的路径中的,并且是虚拟机识别的类库加载到虚拟机内存中。 64 | - **扩展类加载器(Extension ClassLoader)**:负责加载 ```\lib\ext``` 目录下的,或者被 ```java.ext.dirs``` 系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器。 65 | - **应用程序类加载器(Application ClassLoader)**:负责加载用户类路径(ClassPath)上所指定的类库,一般情况下这个就是程序中默认的类加载器。 66 | 67 | > 68 | > 以上加载器互相配合来加载我们自己的应用程序,如果有必要,我们还可以加入自己定义的加载器。这些加载器之间的关系一般如下图示: 69 | > 70 | > ![双亲委派模型](img/双亲委派模型.png) 71 | > 72 | >类加载器的**双亲委派模型(Parent Delegation Model)**:要求除了顶层的启动类加载器外,其余的类加载器都必须有自己的父类加载器。(⚠️,这里类加载器之间的父子关系一般不会以继承(Inheritance)来实现,而是使用组合(Composition)来复用父加载器的代码)。这种模型被广泛使用于几乎所有的Java程序中,但是它并不是一个强制性的约束,只是Java设计者推荐给开发者使用的一种类加载器实现方式。 73 | > 74 | >*双亲委派模型的具体工作过程是:如果一个类收到了加载请求,它首先不会尝试自己去加载这个类,而是把这个请求委派给他的父类加载器去完成,每一层次的加载类都是如此,因此所有的加载请求都会传递给最顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围内找不到需要加载的类)时,子类才会尝试自己去加载。* 75 | > 76 | >好处:java类随着它的类加载器一起具备了一种带有优先层级的层次关系,保证了Java程序的稳定运行。 77 | 78 | ### 7.4.3 破坏双亲委派模型 ### 79 | > OSGi 80 | 81 | 82 | -------------------------------------------------------------------------------- /Chapter8 虚拟机字节码执行引擎.md: -------------------------------------------------------------------------------- 1 | # 深入理解Java虚拟机 # 2 | 3 | --- 4 | 5 | ## Chapter 8 虚拟机字节码执行引擎 ## 6 | 7 | ### 8.1 概述 ### 8 | 9 | > **执行引擎**是Java虚拟机最核心的组成之一。 10 | 11 | ### 8.2 运行时栈帧结构 ### 12 | > **栈帧(Stack Frame)**是用于支持方法调用和方法执行的数据结构。它是虚拟机运行时数据区中的虚拟机栈的栈元素,存储了方法的局部变量表、操作数栈、动态链接和方法返回地址等信息。每一个方法从调用开始到执行完成的过程,就对应着一个栈帧在虚拟机栈里面从入栈道出栈的过程。 13 | > 14 | > 栈帧的概念结构图: 15 | > ![栈帧的概念结构](img/栈帧的概念结构.jpg) 16 | 17 | #### 8.2.1 局部变量表 #### 18 | > 局部变量表是一组变量值存储空间,用于存放方法的参数和方法类定义的局部变量。 19 | > 20 | > 它是以变量槽(Variable Slot)为最小单位,每一个Slot(32位)都应该能放一个 boolean 、byte 、char 、float 、 reference 、 short 、 int 或 returnAddress 类型数据。而至于 long 、double 两种数据则被规定为是64位数据(连续两个32位)。 21 | > *reference类型数据可能食32位,也可能是64位数据* 22 | 23 | #### 8.2.2 操作数栈 #### 24 | >也被称之为操作栈,是一个先进先出(FIFO)的栈。 25 | > 26 | > 操作数栈的最大深度也在编译的时候就被写入到code属性的 ```max_stacks``` 数据项之中。 27 | > 28 | > 在概念模型中,两个栈帧相互之间是完全独立的,但是大多数虚拟机会做一些优化处理,令两个栈帧出现一部分重叠,这样在方法调用时就可以公用一部分数据,无须进行额外的参数复制传递的操作。如下图示: 29 | > 30 | > ![两个栈帧之间的共享数据.](img/两个栈帧之间的共享数据.png) 31 | 32 | #### 8.2.3 动态连接 #### 33 | > 每个栈帧都包含一个运行时常量池中指向该栈帧所属方法的引用,这是为了支持方法调用过程中的**动态连接**。 34 | 35 | #### 8.2.4 方法返回地址 #### 36 | > 当一个方法被执行时,有两种方式推出这个方法: 37 | > 38 | > - 正常完成出口(Normal Method Invocation Completion) 39 | > - 异常完成出口(Abrupt Method Invocation Completion) 40 | 41 | #### 8.2.5 附加信息 ### 42 | > 虚拟机规范允许具体的虚拟机实现增加一些规范里没有描述的信息到栈帧之中。 43 | 44 | ### 8.3 方法调用 ### 45 | > 确定被调用方法的版本(即调用哪一个方法)。 46 | 47 | #### 8.3.1 方法解析 #### 48 | > 调用目标在程序写好、编译器进行编译时就确定下来,这种方法的调用称之为**解析(Resolution)**。 49 | > 50 | > 简单总结就是:**编译器可知,运行期不可变**。 51 | > 52 | > 在Java中符合这种要求的方法主要有:静态方法和私有方法 53 | 54 | #### 8.3.2 分派 #### 55 | > 56 | 57 | ##### 1)、 静态分派 ##### 58 | > 59 | > ```Human man = new Man();``` 60 | > 61 | > **静态类型**:```Human``` 62 | > 63 | > **实际类型**:```Man``` 64 | > 65 | > 在编译阶段,Javac编译器就根据参数的静态类型决定使用哪个重载版本。 66 | 67 | ##### 2)、 动态分派 ##### 68 | > 69 | > 在运行期间根据实际类型确定方法执行版本的分配过程称为动态分派。 70 | 71 | ##### 3)、 单分派与多分派 ##### 72 | > **单分派**是根据一个宗量对目标方法进行选择。 73 | > 74 | > **多分派**则是根据多于一个的宗量对目标方法进行选择。 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # understandingJVM 2 | 《深入理解Java虚拟机》读书笔记 3 | -------------------------------------------------------------------------------- /example.object: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/example.object -------------------------------------------------------------------------------- /img/Cache Coherence.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/img/Cache Coherence.jpg -------------------------------------------------------------------------------- /img/Class文件格式.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/img/Class文件格式.jpg -------------------------------------------------------------------------------- /img/Class文件的访问标志.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/img/Class文件的访问标志.jpg -------------------------------------------------------------------------------- /img/GC Root Tracing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/img/GC Root Tracing.jpg -------------------------------------------------------------------------------- /img/HotSpot JVM 1.6 GC .jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/img/HotSpot JVM 1.6 GC .jpg -------------------------------------------------------------------------------- /img/Java runtime data area.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/img/Java runtime data area.png -------------------------------------------------------------------------------- /img/Java虚拟机提供的语言无关性.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/img/Java虚拟机提供的语言无关性.png -------------------------------------------------------------------------------- /img/access object by handle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/img/access object by handle.jpg -------------------------------------------------------------------------------- /img/access object by pointer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/img/access object by pointer.jpg -------------------------------------------------------------------------------- /img/mat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/img/mat.png -------------------------------------------------------------------------------- /img/oom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/img/oom.png -------------------------------------------------------------------------------- /img/两个栈帧之间的共享数据.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/img/两个栈帧之间的共享数据.png -------------------------------------------------------------------------------- /img/双亲委派模型.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/img/双亲委派模型.png -------------------------------------------------------------------------------- /img/栈帧的概念结构.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/img/栈帧的概念结构.jpg -------------------------------------------------------------------------------- /img/类的生命周期.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/img/类的生命周期.jpg -------------------------------------------------------------------------------- /img/线程、主内存、工作内存之间的关系.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/img/线程、主内存、工作内存之间的关系.png -------------------------------------------------------------------------------- /nio-data.txt: -------------------------------------------------------------------------------- 1 | New String to write to file... 2 | 当前毫秒数:15022008793464 -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/FutureTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM; 2 | 3 | import java.util.concurrent.Callable; 4 | import java.util.concurrent.ExecutionException; 5 | //import java.util.concurrent.ExecutorService; 6 | //import java.util.concurrent.Executors; 7 | //import java.util.concurrent.Future; 8 | import java.util.concurrent.FutureTask; 9 | 10 | /** 11 | * http://www.cnblogs.com/dolphin0520/p/3949310.html 12 | * 13 | * @author taomk 2017年8月24日 下午7:15:03 14 | * 15 | */ 16 | public class FutureTest { 17 | 18 | public static void main(String[] args) { 19 | 20 | Task task = new Task(); 21 | 22 | // 第一种方式来使用Task + Future,通过Executor来使用 23 | // ExecutorService executors = Executors.newCachedThreadPool(); 24 | // Future result = executors.submit(task); 25 | // executors.shutdown(); 26 | 27 | // 第二种方式来使用FutureTask,通过Thread来使用 28 | FutureTask result = new FutureTask(task); 29 | Thread taskThread = new Thread(result); 30 | taskThread.start(); 31 | 32 | try { 33 | Thread.sleep(1000); 34 | } catch (InterruptedException e) { 35 | e.printStackTrace(); 36 | } 37 | 38 | System.out.println("Main thread is running..."); 39 | 40 | try { 41 | System.out.println("Task result : " + result.get()); 42 | } catch (InterruptedException e) { 43 | e.printStackTrace(); 44 | } catch (ExecutionException e) { 45 | e.printStackTrace(); 46 | } 47 | 48 | System.out.println("All thread is end."); 49 | } 50 | } 51 | 52 | class Task implements Callable{ 53 | 54 | @Override 55 | public Integer call() throws Exception { 56 | 57 | System.out.println("Task is running..."); 58 | Thread.sleep(2*1000); 59 | int sum = 0; 60 | for (int i = 1; i <= 100; i++) { 61 | sum += i; 62 | } 63 | 64 | return sum; 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/annotation/Client.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.annotation; 2 | 3 | /** 4 | * 测试类 5 | * @author taomk 2017年7月26日 下午8:38:18 6 | * 7 | */ 8 | public class Client { 9 | 10 | public static void main(String[] args) { 11 | getGreetingMessage(GeetingAnnotationTest.class); 12 | } 13 | 14 | public static void getGreetingMessage(Class clazz) { 15 | 16 | if(clazz.isAnnotationPresent(Greeting.class)){ 17 | Greeting greetingMsg = clazz.getAnnotation(Greeting.class); 18 | System.out.println("message:" + greetingMsg.message()); 19 | System.out.println("sayHi:" + greetingMsg.sayHi()); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/annotation/GeetingAnnotationTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.annotation; 2 | 3 | /** 4 | * 业务使用类 5 | * @author taomk 2017年7月26日 下午8:35:04 6 | * 7 | */ 8 | @Greeting(message="Test" , sayHi="233333") 9 | public class GeetingAnnotationTest { 10 | 11 | void foo(){ 12 | System.out.println("bar~"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/annotation/Greeting.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Inherited; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * 自定义注解 12 | * @author taomk 2017年7月26日 下午8:28:16 13 | * 14 | */ 15 | @Documented 16 | @Retention(value = RetentionPolicy.RUNTIME) 17 | @Target(ElementType.TYPE) 18 | @Inherited 19 | public @interface Greeting { 20 | 21 | /** 22 | * 自定义信息 23 | * @return 24 | */ 25 | public String message() default "~"; 26 | 27 | /** 28 | * 打招呼 29 | * @return 30 | */ 31 | public String sayHi() default "Hi~"; 32 | } 33 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/annotation/NameCheckProcessor.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.annotation; 2 | 3 | import java.util.Set; 4 | 5 | import javax.annotation.processing.AbstractProcessor; 6 | import javax.annotation.processing.ProcessingEnvironment; 7 | import javax.annotation.processing.RoundEnvironment; 8 | import javax.annotation.processing.SupportedAnnotationTypes; 9 | import javax.annotation.processing.SupportedSourceVersion; 10 | import javax.lang.model.SourceVersion; 11 | import javax.lang.model.element.Element; 12 | import javax.lang.model.element.TypeElement; 13 | 14 | /** 15 | * 注解处理器 16 | * 17 | * @author taomk 2017-1-29 18 | * 19 | */ 20 | // 表示对所有的annotations都感兴趣 21 | @SupportedAnnotationTypes("*") 22 | // 表示只支持JDK 1.8的Java代码 23 | @SupportedSourceVersion(SourceVersion.RELEASE_8) 24 | public class NameCheckProcessor extends AbstractProcessor { 25 | 26 | private NameChecker nameChecker; 27 | 28 | /* 29 | * (non-Javadoc) 30 | * 31 | * @see javax.annotation.processing.AbstractProcessor#init(javax.annotation. 32 | * processing.ProcessingEnvironment) 33 | */ 34 | @Override 35 | public synchronized void init(ProcessingEnvironment processingEnv) { 36 | super.init(processingEnv); 37 | // 初始化名称检查插件 38 | nameChecker = new NameChecker(processingEnv); 39 | } 40 | 41 | /* (non-Javadoc) 42 | * @see javax.annotation.processing.AbstractProcessor#process(java.util.Set, javax.annotation.processing.RoundEnvironment) 43 | */ 44 | @Override 45 | public boolean process(Set annotations, RoundEnvironment roundEnv) { 46 | if(!roundEnv.processingOver()){ 47 | for (Element typeElement : roundEnv.getRootElements()) { 48 | // 对输入的语法树的各个节点进行名称检查 49 | nameChecker.checkName(typeElement); 50 | } 51 | } 52 | return false; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/annotation/NameChecker.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.annotation; 2 | 3 | import javax.annotation.processing.Messager; 4 | import javax.annotation.processing.ProcessingEnvironment; 5 | import javax.lang.model.element.Element; 6 | import javax.lang.model.element.TypeElement; 7 | import javax.lang.model.util.ElementScanner8; 8 | 9 | /** 10 | * 命名检查器实现 11 | * 12 | * @author taomk 2017-1-29 13 | * 14 | */ 15 | public class NameChecker { 16 | 17 | private final Messager messager; 18 | 19 | NameCheckScanner nameCheckScanner = new NameCheckScanner(); 20 | 21 | public NameChecker(ProcessingEnvironment processingEnv) { 22 | this.messager = processingEnv.getMessager(); 23 | } 24 | 25 | /** 26 | * 委托给nameCheckScanner完成对命名的检查 27 | * 28 | * @param typeElement 29 | */ 30 | public void checkName(Element typeElement) { 31 | nameCheckScanner.scan(typeElement); 32 | } 33 | 34 | private class NameCheckScanner extends ElementScanner8{ 35 | 36 | @Override 37 | public Void visitType(TypeElement e, Void p) { 38 | scan(e.getTypeParameters(), p); 39 | checkCamelCase(e, true); 40 | super.visitType(e, p); 41 | return null; 42 | } 43 | 44 | /** 45 | * 检查传入的Element是否符合驼峰命名法则,如果不符合,则输出警告信息 46 | * @param e 47 | * @param b 48 | */ 49 | private void checkCamelCase(TypeElement e, boolean initialCaps) { 50 | String name = e.getSimpleName().toString(); 51 | @SuppressWarnings("unused") 52 | boolean previousUpper = false; 53 | boolean conventional = true; 54 | int firstCodePoint = name.codePointAt(0); 55 | 56 | if(Character.isUpperCase(firstCodePoint)){ 57 | previousUpper = true; 58 | if(!initialCaps){ 59 | messager.printMessage(javax.tools.Diagnostic.Kind.WARNING, "名称“"+name+"”应当以小写字母开头", e); 60 | return; 61 | } 62 | }else if(Character.isLowerCase(firstCodePoint)){ 63 | if(initialCaps){ 64 | messager.printMessage(javax.tools.Diagnostic.Kind.WARNING, "名称“"+name+"”应当以大写字母开头", e); 65 | return; 66 | } 67 | }else{ 68 | conventional = false; 69 | } 70 | 71 | if(conventional){ 72 | int cp = firstCodePoint; 73 | for (int i = Character.charCount(cp); i < name.length(); i+=Character.charCount(cp)) { 74 | cp = name.codePointAt(i); 75 | if(Character.isUpperCase(cp)){ 76 | conventional = false; 77 | break; 78 | } 79 | previousUpper = false; 80 | } 81 | } 82 | 83 | if(!conventional){ 84 | messager.printMessage(javax.tools.Diagnostic.Kind.WARNING, "名称“"+name+"”应当符合驼峰式命名规则(Camel Case Names)", e); 85 | return; 86 | } 87 | } 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/autobox/Test.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.autobox; 2 | 3 | /** 4 | * https://zhuanlan.zhihu.com/p/28645185?group_id=882741314054152192 5 | * 6 | * @author taomk 2017年8月21日 下午6:41:28 7 | * 8 | */ 9 | public class Test { 10 | 11 | public static long test(long value) { 12 | return value; 13 | } 14 | 15 | @SuppressWarnings("null") 16 | public static void main(String[] args) { 17 | Long value = null; 18 | // ... 19 | test(value); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/blockqueue/BlockingQueueTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.blockqueue; 2 | 3 | import java.util.concurrent.ArrayBlockingQueue; 4 | import java.util.concurrent.BlockingQueue; 5 | 6 | /** 7 | * @author taomk 2017年5月22日 下午4:18:12 8 | * 9 | */ 10 | public class BlockingQueueTest { 11 | 12 | public static void main(String[] args) { 13 | 14 | final BlockingQueue queue = new ArrayBlockingQueue(3); 15 | 16 | for (int i = 0; i < 2; i++) { 17 | new Thread() { 18 | public void run() { 19 | while (true) { 20 | try { 21 | Thread.sleep((long) (Math.random() * 1000)); 22 | System.out.println(Thread.currentThread().getName() + "准备放数据!"); 23 | queue.put(1); 24 | System.out.println( 25 | Thread.currentThread().getName() + "已经放了数据," + "队列目前有" + queue.size() + "个数据"); 26 | } catch (InterruptedException e) { 27 | e.printStackTrace(); 28 | } 29 | 30 | } 31 | } 32 | 33 | }.start(); 34 | } 35 | 36 | new Thread() { 37 | public void run() { 38 | while (true) { 39 | try { 40 | // 将此处的睡眠时间分别改为100和1000,观察运行结果 41 | Thread.sleep(100); 42 | System.out.println(Thread.currentThread().getName() + "准备取数据!"); 43 | queue.take(); 44 | System.out 45 | .println(Thread.currentThread().getName() + "已经取走数据," + "队列目前有" + queue.size() + "个数据"); 46 | } catch (InterruptedException e) { 47 | e.printStackTrace(); 48 | } 49 | } 50 | } 51 | 52 | }.start(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/cache/LocalCache.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.cache; 2 | 3 | import java.io.Serializable; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | /** 10 | * 成员变量或者是局部变量来实现的本地缓存 11 | * 12 | * https://zhuanlan.zhihu.com/p/27457401 13 | * 14 | * @author taomk 2017年7月20日 下午8:55:16 15 | * 16 | */ 17 | public class LocalCache { 18 | 19 | /** 20 | * 模拟数据库,里面存储的是 com.taomk.understandingJVM.cache.Goods 21 | */ 22 | Map goodsInDB = new HashMap(); 23 | 24 | /** 25 | * 缓存 26 | */ 27 | Map localCacheStoreMap = new HashMap(); 28 | 29 | LocalCache() { 30 | 31 | // init 32 | Goods nike = new Goods("10001", "20001", "nike"); 33 | goodsInDB.put(nike.getId(), nike); 34 | 35 | Goods adidas = new Goods("10002", "20001", "adidas"); 36 | goodsInDB.put(adidas.getId(), adidas); 37 | 38 | Goods nb = new Goods("10003", "20001", "new balance"); 39 | goodsInDB.put(nb.getId(), nb); 40 | 41 | Goods ua = new Goods("10004", "20001", "under armour"); 42 | goodsInDB.put(ua.getId(), ua); 43 | 44 | Goods armani = new Goods("10005", "20002", "armani"); 45 | goodsInDB.put(armani.getId(), armani); 46 | 47 | Goods gucci = new Goods("10006", "20003", "gucci"); 48 | goodsInDB.put(gucci.getId(), gucci); 49 | } 50 | 51 | public static void main(String[] args) { 52 | 53 | LocalCache cacheTest = new LocalCache(); 54 | System.out.println("第一次执行:"); 55 | long startTime = System.currentTimeMillis(); 56 | cacheTest.useLocalCache(); 57 | long endTime = System.currentTimeMillis(); 58 | System.out.println("\t耗时:(ms)" + (endTime-startTime)); 59 | 60 | System.out.println("第二次执行:"); 61 | startTime = System.currentTimeMillis(); 62 | cacheTest.useLocalCache(); 63 | endTime = System.currentTimeMillis(); 64 | System.out.println("\t耗时:(ms)" + (endTime-startTime)); 65 | 66 | } 67 | 68 | public Object useLocalCache() { 69 | 70 | List infoList = this.getInfoList(); 71 | 72 | Object valueObject = null; 73 | for (String id : infoList) { 74 | if (localCacheStoreMap.containsKey(id)) {// 缓存命中,从缓存中获取数据 75 | System.out.println("\tGet from localCache : "); 76 | valueObject = localCacheStoreMap.get(id); 77 | System.out.println("\t\tvalueObject : " + valueObject); 78 | } else { 79 | System.out.println("\tGet from DB : "); 80 | valueObject = this.getInfoFromDB(id); 81 | System.out.println("\t\tvalueObject : " + valueObject); 82 | localCacheStoreMap.put(id, valueObject); 83 | } 84 | } 85 | 86 | return valueObject; 87 | } 88 | 89 | /** 90 | * 从DB中获取数据 91 | * 92 | * @return 93 | */ 94 | private Object getInfoFromDB(String id) { 95 | // 可能比较耗时 96 | try { 97 | Thread.sleep(1 * 1000); 98 | } catch (InterruptedException e) { 99 | e.printStackTrace(); 100 | } 101 | return goodsInDB.get(id); 102 | } 103 | 104 | /** 105 | * 获取Info List,有可能是一个ID List 106 | * 107 | * @return 108 | */ 109 | public List getInfoList() { 110 | 111 | List idList = new ArrayList(); 112 | idList.add("10001"); 113 | idList.add("10002"); 114 | idList.add("10003"); 115 | 116 | return idList; 117 | } 118 | } 119 | 120 | class Goods implements Serializable { 121 | 122 | /** 123 | * 自动生成的序列号 124 | */ 125 | private static final long serialVersionUID = 6572328463371831346L; 126 | 127 | private String id; 128 | private String shopId; 129 | private String name; 130 | 131 | public Goods(String id, String shopId, String name) { 132 | super(); 133 | this.id = id; 134 | this.shopId = shopId; 135 | this.name = name; 136 | } 137 | 138 | public String getId() { 139 | return id; 140 | } 141 | 142 | public void setId(String id) { 143 | this.id = id; 144 | } 145 | 146 | public String getShopId() { 147 | return shopId; 148 | } 149 | 150 | public void setShopId(String shopId) { 151 | this.shopId = shopId; 152 | } 153 | 154 | public String getName() { 155 | return name; 156 | } 157 | 158 | public void setName(String name) { 159 | this.name = name; 160 | } 161 | 162 | @Override 163 | public String toString() { 164 | return "Goods [id=" + id + ", shopId=" + shopId + ", name=" + name + "]"; 165 | } 166 | 167 | } -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/candy/AutoPackage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.taomk.understandingJVM.candy; 5 | 6 | /** 7 | * 自动装箱的陷阱 8 | * 9 | * @author taomk 2017-1-26 10 | * 11 | */ 12 | public class AutoPackage { 13 | 14 | public static void main(String[] args) { 15 | Integer a = 1; 16 | Integer b = 2; 17 | Integer c = 3; 18 | Integer d = 3; 19 | Integer e = 321; 20 | Integer f = 321; 21 | Long g = 3L; 22 | 23 | System.out.println(c == d); //true 24 | System.out.println(e == f); //false 25 | System.out.println(c == (a+b)); //true 26 | System.out.println(c.equals(a+b));//true 27 | System.out.println(g == (a+b)); //true 28 | System.out.println(g.equals(a+b)); //false 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/atomic/AtomicStudy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.atomic; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.atomic.AtomicInteger; 6 | 7 | /** 8 | *
http://ifeve.com/atomic-operation/
9 | * @author taomk 2017年5月27日 下午4:16:30 10 | * 11 | */ 12 | public class AtomicStudy { 13 | 14 | private AtomicInteger atomicI = new AtomicInteger(); 15 | private int commonI; 16 | private volatile int volatileI; 17 | 18 | private static final int THREAD_COUNT = 100; 19 | 20 | public static void main(String[] args) { 21 | AtomicStudy counter = new AtomicStudy(); 22 | List threadList = new ArrayList(THREAD_COUNT); 23 | 24 | for (int i = 0; i < THREAD_COUNT; i++) { 25 | Thread t = new Thread(new Runnable() { 26 | 27 | @Override 28 | public void run() { 29 | for (int j = 0; j < 10*1000; j++) { 30 | // counter.commonCount(); 31 | counter.safeCount(); 32 | counter.volatileCount(); 33 | counter.atomicCount(); 34 | } 35 | } 36 | }); 37 | threadList.add(t); 38 | } 39 | 40 | for (Thread t : threadList) { 41 | t.start(); 42 | } 43 | 44 | for (Thread t : threadList) { 45 | try { 46 | t.join(); 47 | } catch (InterruptedException e) { 48 | e.printStackTrace(); 49 | } 50 | } 51 | 52 | System.out.println("commonI : " + counter.commonI); 53 | System.out.println("volatileI : " + counter.volatileI); 54 | System.out.println("atomicI : " + counter.atomicI.get()); 55 | 56 | } 57 | 58 | /** 59 | * 普通计数方式 60 | */ 61 | @SuppressWarnings("unused") 62 | private void commonCount(){ 63 | commonI++; 64 | } 65 | 66 | /** 67 | * volatile计数方式 68 | */ 69 | private void volatileCount(){ 70 | volatileI++; 71 | } 72 | 73 | /** 74 | * atomic计数方式 75 | */ 76 | private void atomicCount(){ 77 | atomicI.incrementAndGet(); 78 | } 79 | 80 | /** 81 | * 安全的计数方式 82 | */ 83 | private void safeCount(){ 84 | while(true){ 85 | int i = atomicI.get(); 86 | boolean suc = atomicI.compareAndSet(i, ++i); 87 | if(suc){ 88 | break; 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/cow/BlackListServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.cow; 2 | 3 | import java.util.ArrayList; 4 | import java.util.concurrent.CopyOnWriteArrayList; 5 | 6 | /** 7 | * 8 | * 使用CopyOnWrite机制来实现黑名单 9 | * 10 | * @author taomk 2017年6月5日 下午7:27:22 11 | * 12 | */ 13 | public class BlackListServiceImpl { 14 | 15 | private static CopyOnWriteArrayList blackList = new CopyOnWriteArrayList(); 16 | 17 | public static int size(){ 18 | return blackList.size(); 19 | } 20 | 21 | public static boolean isInBlackList(String target){ 22 | return blackList.contains(target); 23 | } 24 | 25 | public static void addIntoBlackList(String target){ 26 | blackList.add(target); 27 | } 28 | 29 | public static void addIntoBlackListBulk(ArrayList targetList){ 30 | blackList.addAll(targetList); 31 | } 32 | 33 | public static void removeFromBlackList(String target){ 34 | blackList.remove(target); 35 | } 36 | 37 | public static void main(String[] args) { 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/cow/CopyOnWriteMap.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.cow; 2 | 3 | import java.util.Collection; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | import java.util.Set; 7 | 8 | /** 9 | *
 10 |  * 自定义实现一个CopyOnWrite的Map
 11 |  * 
 12 |  * 当put元素时,遵守 Copy-On-Write 的原理,按照以下步骤进行:
 13 |  * 1,加锁
 14 |  * 2,创建有一个新的map
 15 |  * 3,将原map内容复制到新的map
 16 |  * 4,将元素put进入新的map
 17 |  * 5,将原map指向新map
 18 |  * 6,返回添加的value
 19 |  * 7,解锁
 20 |  * 
 21 |  * @see http://ifeve.com/java-copy-on-write/comment-page-1/#comment-27735
 22 |  * 
23 | * 24 | * @author taomk 2017年6月15日 下午3:55:30 25 | * 26 | */ 27 | public class CopyOnWriteMap implements Map, Cloneable { 28 | 29 | private Map internalMap; 30 | 31 | public CopyOnWriteMap(){ 32 | internalMap = new HashMap(); 33 | } 34 | 35 | // 自定义初始容量的Map 36 | public CopyOnWriteMap(int capacity){ 37 | internalMap = new HashMap(capacity); 38 | } 39 | 40 | @Override 41 | public int size() { 42 | return internalMap.size(); 43 | } 44 | 45 | @Override 46 | public boolean isEmpty() { 47 | return internalMap.isEmpty(); 48 | } 49 | 50 | @Override 51 | public boolean containsKey(Object key) { 52 | return internalMap.containsKey(key); 53 | } 54 | 55 | @Override 56 | public boolean containsValue(Object value) { 57 | return internalMap.containsValue(value); 58 | } 59 | 60 | @Override 61 | public V get(Object key) { 62 | return internalMap.get(key); 63 | } 64 | 65 | /* (non-Javadoc) 66 | * @see java.util.Map#put(java.lang.Object, java.lang.Object) 67 | * 68 | */ 69 | @Override 70 | public V put(K key, V value) { 71 | synchronized (this) { 72 | Map newMap = new HashMap(internalMap); 73 | V val = newMap.put(key, value); 74 | internalMap = newMap; 75 | return val; 76 | } 77 | } 78 | 79 | @Override 80 | public V remove(Object key) { 81 | synchronized (this) { 82 | Map newMap = new HashMap(internalMap); 83 | V val = newMap.remove(key); 84 | internalMap = newMap; 85 | return val; 86 | } 87 | } 88 | 89 | @Override 90 | public void putAll(Map m) { 91 | synchronized (this) { 92 | Map newMap = new HashMap(internalMap); 93 | newMap.putAll(m); 94 | internalMap = newMap; 95 | } 96 | } 97 | 98 | @Override 99 | public void clear() { 100 | synchronized (this) { 101 | Map newMap = new HashMap(internalMap); 102 | newMap.clear(); 103 | internalMap = newMap; 104 | } 105 | 106 | } 107 | 108 | @Override 109 | public Set keySet() { 110 | return internalMap.keySet(); 111 | } 112 | 113 | @Override 114 | public Collection values() { 115 | return internalMap.values(); 116 | } 117 | 118 | @Override 119 | public Set> entrySet() { 120 | return internalMap.entrySet(); 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/executor/CachedThreadExecutorTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.executor; 2 | 3 | import java.util.concurrent.Executors; 4 | 5 | /** 6 | *
 7 |  * 测试: {@link java.util.concurrent.Executors.newCachedThreadPool()}
 8 |  * 
 9 |  * 返回的结果表明newFixedThreadPool创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
10 |  * 
11 |  * 数量设置一般和Runtime.getRuntime().availableProcessors();一致
12 |  * 
13 | * @author taomk 2017年4月27日 下午3:10:30 14 | * 15 | */ 16 | public class CachedThreadExecutorTest { 17 | 18 | public static void main(String[] args) { 19 | 20 | java.util.concurrent.ExecutorService fixedExecutorService = Executors.newCachedThreadPool(); 21 | 22 | for (int i = 0; i < 10; i++) { 23 | 24 | try { 25 | Thread.sleep(1000); 26 | } catch (InterruptedException e) { 27 | e.printStackTrace(); 28 | } 29 | 30 | final int index = i; 31 | 32 | fixedExecutorService.execute(new Runnable() { 33 | 34 | @Override 35 | public void run() { 36 | System.out.println(Thread.currentThread().getName() + " " + index + " is running..."); 37 | } 38 | }); 39 | } 40 | 41 | fixedExecutorService.shutdownNow(); 42 | System.out.println("Outter:" + Thread.currentThread().getName() + " is running... "); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/executor/FixedThreadExecutorTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.executor; 2 | 3 | import java.util.concurrent.Executors; 4 | 5 | /** 6 | *
 7 |  * 测试: {@link java.util.concurrent.Executors.newFixedThreadPool()}
 8 |  * 
 9 |  * 返回的结果表明newFixedThreadPool创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
10 |  * 
11 |  * 数量设置一般和Runtime.getRuntime().availableProcessors();一致
12 |  * 
13 | * @author taomk 2017年4月27日 下午3:10:30 14 | * 15 | */ 16 | public class FixedThreadExecutorTest { 17 | 18 | public static void main(String[] args) { 19 | 20 | int coreCount = Runtime.getRuntime().availableProcessors(); 21 | 22 | System.out.println("Thread pool count : " + coreCount); 23 | 24 | java.util.concurrent.ExecutorService fixedExecutorService = Executors.newFixedThreadPool(coreCount); 25 | 26 | for (int i = 0; i < 10; i++) { 27 | 28 | fixedExecutorService.execute(new Runnable() { 29 | 30 | @Override 31 | public void run() { 32 | 33 | System.out.println(Thread.currentThread().getName() + " is running... "); 34 | try { 35 | Thread.sleep(500); 36 | } catch (InterruptedException e) { 37 | } 38 | } 39 | }); 40 | } 41 | 42 | fixedExecutorService.shutdown(); 43 | 44 | System.out.println("Outter : " + Thread.currentThread().getName() + " is running... "); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/executor/ScheduledThreadExecutorTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.executor; 2 | 3 | import java.util.concurrent.Executors; 4 | import java.util.concurrent.TimeUnit; 5 | 6 | /** 7 | *
 8 |  * 测试: {@link java.util.concurrent.Executors.newScheduledThreadPool()}
 9 |  * 
10 |  * 创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
11 |  * 
12 | * @author taomk 2017年4月27日 下午6:34:37 13 | * 14 | */ 15 | public class ScheduledThreadExecutorTest { 16 | 17 | public static void main(String[] args) { 18 | 19 | // 延迟执行 20 | java.util.concurrent.ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3); 21 | scheduledExecutorService.schedule(new Runnable() { 22 | 23 | @Override 24 | public void run() { 25 | System.out.println(Thread.currentThread().getName() + " is running , delay 1 second. "); 26 | } 27 | }, 1, TimeUnit.SECONDS); 28 | 29 | // 定期执行 30 | // java.util.concurrent.ScheduledExecutorService scheduledAtFixedRateExecutorService = Executors.newScheduledThreadPool(5); 31 | // scheduledAtFixedRateExecutorService.scheduleAtFixedRate(new Runnable() { 32 | // 33 | // @Override 34 | // public void run() { 35 | // System.out.println(Thread.currentThread().getName() + " is running , every 3 seconds. "); 36 | // } 37 | // }, 0, 3, TimeUnit.SECONDS); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/executor/SingleThreadExecutorTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.executor; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | /** 7 | *
 8 |  * 测试: {@link java.util.concurrent.Executors.newSingleThreadExecutor()}
 9 |  * 
10 |  * 返回的结果表明每次执行的线程都是同一个。
11 |  * 
12 | * 13 | * @author taomk 2017年4月25日 下午10:08:50 14 | * 15 | */ 16 | public class SingleThreadExecutorTest { 17 | 18 | public static void main(String[] args) { 19 | 20 | ExecutorService singleThreadExecurot = Executors.newSingleThreadExecutor(); 21 | 22 | for (int i = 0; i < 10; i++) { 23 | singleThreadExecurot.execute(new Runnable() { 24 | 25 | @Override 26 | public void run() { 27 | System.out.println(Thread.currentThread().getName() + " is running... "); 28 | try { 29 | Thread.sleep(500); 30 | } catch (InterruptedException e) { 31 | e.printStackTrace(); 32 | } 33 | } 34 | });; 35 | } 36 | 37 | System.out.println("Outter:" + Thread.currentThread().getName() + " is running... "); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/forkjoin/ForkJoinStudy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.forkjoin; 2 | 3 | import java.util.concurrent.ExecutionException; 4 | import java.util.concurrent.ForkJoinPool; 5 | import java.util.concurrent.Future; 6 | import java.util.concurrent.RecursiveTask; 7 | 8 | /** 9 | * http://ifeve.com/talk-concurrency-forkjoin/ 10 | * 11 | * @author taomk 2017年6月2日 下午3:21:27 12 | * 13 | */ 14 | public class ForkJoinStudy extends RecursiveTask { 15 | 16 | private static final long serialVersionUID = 1L; 17 | 18 | // 子任务的最大容纳量 19 | private static final int THRESHOLD = 10; 20 | 21 | // 计算范围 22 | private int start, end; 23 | 24 | public ForkJoinStudy(int start, int end) { 25 | this.start = start; 26 | this.end = end; 27 | } 28 | 29 | @Override 30 | protected Integer compute() { 31 | 32 | StringBuffer sb = new StringBuffer(Thread.currentThread().getName() + " compute()..."); 33 | 34 | int sum = 0; 35 | boolean canCompute = (end - start) <= THRESHOLD; 36 | 37 | // 达到可计算范围,则进行计算 38 | if (canCompute) { 39 | for (int i = start; i <= end; i++) { 40 | sum += i; 41 | } 42 | System.out.println(sb.append(sum)); 43 | } else { 44 | // 否则,分裂成2个子任务 45 | int middle = (start + end) / 2; 46 | ForkJoinStudy leftTask = new ForkJoinStudy(start, middle); 47 | ForkJoinStudy rightTask = new ForkJoinStudy(middle+1, end); 48 | // 执行子任务,实际上会调用compute()方法 49 | leftTask.fork(); 50 | rightTask.fork(); 51 | // 等待子任务执行完成,获取计算结果 52 | int leftResult = leftTask.join(); 53 | 54 | int rightResult = rightTask.join(); 55 | // 合并计算结果 56 | sum = leftResult + rightResult; 57 | } 58 | return sum; 59 | } 60 | 61 | public static void main(String[] args) { 62 | // 计算1+2+3+...+100 63 | ForkJoinStudy task = new ForkJoinStudy(1, 100); 64 | ForkJoinPool pool = new ForkJoinPool(); 65 | Future result = pool.submit(task); 66 | 67 | try { 68 | System.out.println("Result : " + result.get()); 69 | } catch (InterruptedException | ExecutionException e) { 70 | e.printStackTrace(); 71 | } 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/lock/TestLocks.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.lock; 2 | 3 | import java.util.concurrent.CyclicBarrier; 4 | import java.util.concurrent.locks.Lock; 5 | import java.util.concurrent.locks.ReentrantLock; 6 | 7 | import static java.lang.System.out; 8 | 9 | /** 10 | * http://blog.csdn.net/kjfcpua/article/details/8541433 11 | * 12 | * @author taomk 2017年6月7日 下午1:34:38 13 | * 14 | */ 15 | public class TestLocks implements Runnable { 16 | 17 | public enum LockType { 18 | JVM, JUC 19 | } 20 | 21 | public static LockType lockType; 22 | 23 | public static final long ITERATIONS = 5L * 1000L * 1000L; 24 | public static long counter = 0L; 25 | 26 | public static final Object jvmLock = new Object(); 27 | // public static final Lock jucLock = new ReentrantLock(false); 28 | public static final Lock jucLock = new ReentrantLock(true); 29 | private static int numThreads; 30 | 31 | private final long iterationLimit; 32 | private final CyclicBarrier barrier; 33 | private long localCounter = 0L; 34 | 35 | public long getLocalCounter() { 36 | return localCounter; 37 | } 38 | 39 | public TestLocks(final CyclicBarrier barrier, final long iterationLimit) { 40 | this.barrier = barrier; 41 | this.iterationLimit = iterationLimit; 42 | } 43 | 44 | public static void main(final String[] args) throws Exception { 45 | // lockType = LockType.valueOf("JVM"); 46 | lockType = LockType.valueOf("JUC"); 47 | numThreads = Integer.parseInt("8"); 48 | 49 | final long start = System.nanoTime(); 50 | runTest(numThreads, ITERATIONS); 51 | final long duration = System.nanoTime() - start; 52 | 53 | out.printf("%d threads, duration %,d (ns)\n", numThreads, duration); 54 | out.printf("%,d ns/op\n", duration / ITERATIONS); 55 | out.printf("%,d ops/s\n", (ITERATIONS * 1000000000L) / duration); 56 | out.println("counter = " + counter); 57 | } 58 | 59 | private static void runTest(final int numThreads, final long iterationLimit) throws Exception { 60 | CyclicBarrier barrier = new CyclicBarrier(numThreads); 61 | Thread[] threads = new Thread[numThreads]; 62 | TestLocks[] testLocks = new TestLocks[numThreads]; 63 | for (int i = 0; i < threads.length; i++) { 64 | testLocks[i] = new TestLocks(barrier, iterationLimit); 65 | threads[i] = new Thread(testLocks[i]); 66 | } 67 | 68 | for (Thread t : threads) { 69 | t.start(); 70 | } 71 | 72 | for (Thread t : threads) { 73 | t.join(); 74 | } 75 | for (int i = 0; i < threads.length; i++) { 76 | out.printf("%d thread, local counter = %,d\n", i, testLocks[i].getLocalCounter()); 77 | } 78 | } 79 | 80 | @Override 81 | public void run() { 82 | try { 83 | barrier.await(); 84 | } catch (Exception e) { 85 | // don't care 86 | } 87 | 88 | switch (lockType) { 89 | case JVM: 90 | jvmLockInc(); 91 | break; 92 | case JUC: 93 | jucLockInc(); 94 | break; 95 | } 96 | } 97 | 98 | private void jvmLockInc() { 99 | 100 | while (true) { 101 | long count = 0; 102 | synchronized (jvmLock) { 103 | ++counter; 104 | count = counter; 105 | } 106 | localCounter++; 107 | if (count >= iterationLimit) { 108 | break; 109 | } 110 | } 111 | } 112 | 113 | private void jucLockInc() { 114 | while (true) { 115 | long count = 0L; 116 | jucLock.lock(); 117 | try { 118 | ++counter; 119 | count = counter; 120 | } finally { 121 | jucLock.unlock(); 122 | } 123 | localCounter++; 124 | if (count >= iterationLimit) { 125 | break; 126 | } 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/map/ConcurrentHashMapIteratorDemo.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.map; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | /** 7 | * 8 | * https://mp.weixin.qq.com/s?__biz=MzIxOTI1NTk5Nw%3D%3D&mid=2650047468&idx=1&sn=6fc28065f97cc27698839c945c892cd8&chksm=8fde263eb8a9af28e7d03ff19433615e8121e4b898c51c4c60b26917bf130c9fcd1e783fcd12&scene=21 9 | * 10 | * @author taomk 2017年9月5日 下午2:50:41 11 | * 12 | */ 13 | public class ConcurrentHashMapIteratorDemo { 14 | 15 | public static void main(String[] args) { 16 | test(); 17 | } 18 | 19 | public static void test() { 20 | 21 | ConcurrentHashMap chm = new ConcurrentHashMap(); 22 | chm.put("a", "C++"); 23 | chm.put("b", "C"); 24 | chm.put("c", "python"); 25 | 26 | Thread t1 = new Thread() { 27 | @Override 28 | public void run() { 29 | for (Map.Entry entry : chm.entrySet()) { 30 | // 弱一致性 31 | // try { 32 | // Thread.sleep(1_000); 33 | // } catch (InterruptedException e) { 34 | // e.printStackTrace(); 35 | // } 36 | System.out.println(entry.getKey() + " : " + entry.getValue()); 37 | } 38 | } 39 | }; 40 | 41 | t1.start(); 42 | 43 | // 确保线程t1启动 44 | try { 45 | Thread.sleep(100); 46 | } catch (InterruptedException e) { 47 | e.printStackTrace(); 48 | } 49 | 50 | chm.put("d", "javascript"); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/map/ConcurrentHashmapStudy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.map; 2 | 3 | import java.util.HashMap; 4 | import java.util.UUID; 5 | 6 | /** 7 | *
 8 |  * 
 9 |  * http://ifeve.com/concurrenthashmap/
10 |  * 
11 | * 12 | * @author taomk 2017年5月27日 下午1:47:55 13 | * 14 | */ 15 | public class ConcurrentHashmapStudy { 16 | 17 | public static void main(String[] args) { 18 | try { 19 | deadLoop(); 20 | } catch (InterruptedException e) { 21 | System.err.println(e.toString()); 22 | } 23 | } 24 | 25 | 26 | /** 27 | * 演示HashMap引起的死循环 28 | * @throws InterruptedException 29 | */ 30 | public static void deadLoop() throws InterruptedException{ 31 | 32 | // 初始容量为2 33 | final HashMap map = new HashMap(2); 34 | 35 | Thread t = new Thread(new Runnable() { 36 | 37 | @Override 38 | public void run() { 39 | 40 | for (int i = 0; i < 10000; i++) { 41 | 42 | new Thread(new Runnable() { 43 | 44 | @Override 45 | public void run() { 46 | map.put(UUID.randomUUID().toString(), ""); 47 | System.out.println("HashMap dead loop demo : inner ."); 48 | } 49 | 50 | }, "HashMap dead loop demo : " + i).start(); 51 | 52 | } 53 | System.out.println("HashMap dead loop demo : outter ."); 54 | } 55 | 56 | }, "HashMap Dead Loop Demo. "); 57 | 58 | t.start(); 59 | 60 | t.join(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/task/consumeAndProducer/multi/Client.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.task.consumeAndProducer.multi; 2 | 3 | /** 4 | * 客户端-测试类 5 | * 6 | * @author taomk 2017年6月20日 下午10:14:07 7 | * 8 | */ 9 | public class Client { 10 | 11 | public static void main(String[] args) { 12 | 13 | Resource resource = new Resource(); 14 | 15 | Producer p = new Producer(resource); 16 | Consumer c = new Consumer(resource); 17 | 18 | // 三个生产者同时生产 19 | new Thread(p).start(); 20 | new Thread(p).start(); 21 | new Thread(p).start(); 22 | 23 | // 四个消费同时消费 24 | new Thread(c).start(); 25 | new Thread(c).start(); 26 | new Thread(c).start(); 27 | new Thread(c).start(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/task/consumeAndProducer/multi/Consumer.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.task.consumeAndProducer.multi; 2 | 3 | /** 4 | * 消费者(多个模式) 5 | * 6 | * @author taomk 2017年6月20日 下午10:11:36 7 | * 8 | */ 9 | public class Consumer extends Thread { 10 | private Resource resource; 11 | 12 | public Consumer(Resource r) { 13 | this.resource = r; 14 | } 15 | 16 | @Override 17 | public void run() { 18 | // 消费者一直消费生产的物料 19 | for (;;) { 20 | resource.consume(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/task/consumeAndProducer/multi/Producer.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.task.consumeAndProducer.multi; 2 | 3 | /** 4 | * 生产者(多个模式) 5 | * 6 | * @author taomk 2017年6月20日 下午10:07:58 7 | * 8 | */ 9 | public class Producer implements Runnable { 10 | 11 | private Resource resource; 12 | 13 | public Producer(Resource r) { 14 | this.resource = r; 15 | } 16 | 17 | /* 18 | * (non-Javadoc) 19 | * 20 | * @see java.lang.Runnable#run() 21 | */ 22 | @Override 23 | public void run() { 24 | // 生产者的任务是:一直印钱 25 | while (true) { 26 | resource.product("Print Money ..."); 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/task/consumeAndProducer/multi/Resource.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.task.consumeAndProducer.multi; 2 | 3 | /** 4 | * 资源类(多个生产者和消费者,通过synchronized关键字来实现) 5 | * 6 | * @author taomk 2017年6月20日 下午7:52:14 7 | * 8 | */ 9 | public class Resource { 10 | 11 | private String resourceName; 12 | private int resourceCount; 13 | private boolean hasResource; 14 | 15 | /** 16 | * 生产者生产资源 17 | * 18 | * @param name 19 | * 资源名称 20 | */ 21 | public synchronized void product(String name) { 22 | 23 | // 如果库存还有资源,说明消费者还没有消费完成,就等待不生产 24 | // 此处循环判断,可以避免生产者重复生产问题 25 | while (hasResource) { 26 | try { 27 | this.wait(); 28 | } catch (InterruptedException e) { 29 | e.printStackTrace(); 30 | } 31 | } 32 | 33 | // 库存数量加1 34 | this.resourceCount++; 35 | // 库存的物料名称 36 | this.resourceName = name + String.valueOf(resourceCount); 37 | System.out.println(Thread.currentThread().getName() + " 生产了 " + this.resourceName); 38 | // 还有库存 39 | hasResource = true; 40 | // 唤醒消费者可以消费了 41 | notifyAll(); 42 | } 43 | 44 | /** 45 | * 消费者消耗资源 46 | */ 47 | public synchronized void consume() { 48 | // 如果库存资源已经没有了,那么消费者就等待 49 | // 此处循环判断,可以避免消费者多次消费问题 50 | while (!hasResource) { 51 | try { 52 | this.wait(); 53 | } catch (InterruptedException e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | // 资源数量减1 58 | // this.resourceCount--; 59 | System.out.println(Thread.currentThread().getName() + " 消费了 " + this.resourceName); 60 | // 库存已经消耗完毕 61 | hasResource = false; 62 | // 唤醒生产者开始生产 63 | notifyAll(); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/task/consumeAndProducer/multi/ResourceBy2Condition.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.task.consumeAndProducer.multi; 2 | 3 | import java.util.concurrent.locks.Condition; 4 | import java.util.concurrent.locks.Lock; 5 | import java.util.concurrent.locks.ReentrantLock; 6 | 7 | /** 8 | * 生产者-消费者模式(多对多) 9 | * 10 | * @author taomk 2017年6月21日 上午11:09:25 11 | * @description 通过lock获取两个监视器,分别监视生产者和消费者 12 | * 13 | */ 14 | public class ResourceBy2Condition { 15 | 16 | private String resourceName; 17 | private int resourceCount; 18 | private boolean hasResource; 19 | 20 | Lock lock = new ReentrantLock(); 21 | 22 | Condition consumerCondition = lock.newCondition(); 23 | Condition producerCondition = lock.newCondition(); 24 | 25 | public void produce(String resourceName) { 26 | lock.lock(); 27 | try { 28 | while (hasResource) { 29 | producerCondition.await(); 30 | } 31 | 32 | resourceCount++; 33 | this.resourceName = resourceName + resourceCount; 34 | System.out.println(Thread.currentThread().getName() + " produce " + this.resourceName); 35 | hasResource = true; 36 | // 直接唤醒消费者线程 37 | consumerCondition.signal(); 38 | } catch (InterruptedException e) { 39 | e.printStackTrace(); 40 | } finally { 41 | lock.unlock(); 42 | } 43 | } 44 | 45 | public void consume(){ 46 | lock.lock(); 47 | try { 48 | while(!hasResource){ 49 | consumerCondition.await(); 50 | } 51 | System.out.println(Thread.currentThread().getName() + " consume " + this.resourceName); 52 | hasResource = false; 53 | // 直接唤醒生产者线程 54 | producerCondition.signal(); 55 | 56 | } catch (InterruptedException e) { 57 | e.printStackTrace(); 58 | } finally { 59 | lock.unlock(); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/task/consumeAndProducer/single/Client.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.task.consumeAndProducer.single; 2 | 3 | /** 4 | * 客户端-测试类 5 | * @author taomk 2017年6月20日 下午10:14:07 6 | * 7 | */ 8 | public class Client { 9 | 10 | public static void main(String[] args) { 11 | 12 | Resource resource = new Resource(); 13 | 14 | Producer p = new Producer(resource); 15 | Consumer c = new Consumer(resource); 16 | 17 | new Thread(p).start(); 18 | new Thread(c).start(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/task/consumeAndProducer/single/Consumer.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.task.consumeAndProducer.single; 2 | 3 | /** 4 | * 消费者(单一模式) 5 | * 6 | * @author taomk 2017年6月20日 下午10:11:36 7 | * 8 | */ 9 | public class Consumer extends Thread { 10 | private Resource resource; 11 | 12 | public Consumer(Resource r) { 13 | this.resource = r; 14 | } 15 | 16 | @Override 17 | public void run() { 18 | // 消费者一直消费生产的物料 19 | for (;;) { 20 | resource.consume(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/task/consumeAndProducer/single/Producer.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.task.consumeAndProducer.single; 2 | 3 | /** 4 | * 生产者(单一模式) 5 | * 6 | * @author taomk 2017年6月20日 下午10:07:58 7 | * 8 | */ 9 | public class Producer implements Runnable { 10 | 11 | private Resource resource; 12 | 13 | public Producer(Resource r) { 14 | this.resource = r; 15 | } 16 | 17 | /* 18 | * (non-Javadoc) 19 | * 20 | * @see java.lang.Runnable#run() 21 | */ 22 | @Override 23 | public void run() { 24 | // 生产者的任务是:一直印钱 25 | while (true) { 26 | resource.product("Print Money ..."); 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/task/consumeAndProducer/single/Resource.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.task.consumeAndProducer.single; 2 | 3 | /** 4 | * 资源类(单一的生产者和消费者,通过synchronized关键字来实现) 5 | * 6 | * @author taomk 2017年6月20日 下午7:52:14 7 | * 8 | */ 9 | public class Resource { 10 | 11 | private String resourceName; 12 | private int resourceCount; 13 | private boolean hasResource; 14 | 15 | /** 16 | * 生产者生产资源 17 | * 18 | * @param name 19 | * 资源名称 20 | */ 21 | public synchronized void product(String name) { 22 | 23 | // 如果库存还有资源,说明消费者还没有消费完成,就等待不生产 24 | if (hasResource) { 25 | try { 26 | this.wait(); 27 | } catch (InterruptedException e) { 28 | e.printStackTrace(); 29 | } 30 | } 31 | 32 | // 库存数量加1 33 | this.resourceCount++; 34 | // 库存的物料名称 35 | this.resourceName = name + String.valueOf(resourceCount); 36 | System.out.println(Thread.currentThread().getName() + " 生产了 " + this.resourceName); 37 | // 还有库存 38 | hasResource = true; 39 | // 唤醒消费者可以消费了 40 | notifyAll(); 41 | } 42 | 43 | /** 44 | * 消费者消耗资源 45 | */ 46 | public synchronized void consume() { 47 | // 如果库存资源已经没有了,那么消费者就等待 48 | if (!hasResource) { 49 | try { 50 | this.wait(); 51 | } catch (InterruptedException e) { 52 | e.printStackTrace(); 53 | } 54 | } 55 | // 资源数量减1 56 | // this.resourceCount--; 57 | System.out.println(Thread.currentThread().getName() + " 消费了 " + this.resourceName); 58 | // 库存已经消耗完毕 59 | hasResource = false; 60 | // 唤醒生产者开始生产 61 | notifyAll(); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/concurrent/task/consumeAndProducer/single/ResourceByLock.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.concurrent.task.consumeAndProducer.single; 2 | 3 | import java.util.concurrent.locks.Condition; 4 | import java.util.concurrent.locks.ReentrantLock; 5 | 6 | /** 7 | * 资源类(单一的生产者和消费者,通过Lock来实现) 8 | * 9 | * @author taomk 2017年6月20日 下午10:20:21 10 | * 11 | */ 12 | public class ResourceByLock { 13 | 14 | private String resourceName; 15 | private int resourceCount; 16 | private boolean hasResource; 17 | 18 | ReentrantLock lock = new ReentrantLock(); 19 | Condition condition = lock.newCondition(); 20 | 21 | /** 22 | * 生产物料 23 | * 24 | * @param name 25 | * 物料名称 26 | */ 27 | public void produce(String name) { 28 | lock.lock(); 29 | try { 30 | if (hasResource) { 31 | condition.await(); 32 | } 33 | // 库存数量加1 34 | this.resourceCount++; 35 | // 库存的物料名称 36 | this.resourceName = name + String.valueOf(resourceCount); 37 | System.out.println(Thread.currentThread().getName() + " 生产了 " + this.resourceName); 38 | // 还有库存 39 | hasResource = true; 40 | // 唤醒生产者线程 41 | condition.signalAll(); 42 | 43 | } catch (Exception e) { 44 | 45 | } finally { 46 | lock.unlock(); 47 | } 48 | } 49 | 50 | public void consume() { 51 | lock.lock(); 52 | try { 53 | if (!hasResource) { 54 | condition.wait(); 55 | } 56 | System.out.println(Thread.currentThread().getName() + " 消费了 " + this.resourceName); 57 | // 库存已经消耗完毕 58 | hasResource = false; 59 | // 唤醒生产者线程开始生产物料 60 | condition.signalAll(); 61 | } catch (InterruptedException e) { 62 | e.printStackTrace(); 63 | } finally { 64 | lock.unlock(); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/encrypt/Base64.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.encrypt; 2 | 3 | /** 4 | * @author taomk 2017年7月4日 下午7:42:16 5 | * 6 | */ 7 | public class Base64 { 8 | 9 | static private final int BASELENGTH = 128; 10 | static private final int LOOKUPLENGTH = 64; 11 | static private final int TWENTYFOURBITGROUP = 24; 12 | static private final int EIGHTBIT = 8; 13 | static private final int SIXTEENBIT = 16; 14 | static private final int FOURBYTE = 4; 15 | static private final int SIGN = -128; 16 | static private final char PAD = '='; 17 | static private final boolean fDebug = false; 18 | static final private byte[] base64Alphabet = new byte[BASELENGTH]; 19 | static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH]; 20 | 21 | static { 22 | for (int i = 0; i < BASELENGTH; ++i) { 23 | base64Alphabet[i] = -1; 24 | } 25 | for (int i = 'Z'; i >= 'A'; i--) { 26 | base64Alphabet[i] = (byte) (i - 'A'); 27 | } 28 | for (int i = 'z'; i >= 'a'; i--) { 29 | base64Alphabet[i] = (byte) (i - 'a' + 26); 30 | } 31 | 32 | for (int i = '9'; i >= '0'; i--) { 33 | base64Alphabet[i] = (byte) (i - '0' + 52); 34 | } 35 | 36 | base64Alphabet['+'] = 62; 37 | base64Alphabet['/'] = 63; 38 | 39 | for (int i = 0; i <= 25; i++) { 40 | lookUpBase64Alphabet[i] = (char) ('A' + i); 41 | } 42 | 43 | for (int i = 26, j = 0; i <= 51; i++, j++) { 44 | lookUpBase64Alphabet[i] = (char) ('a' + j); 45 | } 46 | 47 | for (int i = 52, j = 0; i <= 61; i++, j++) { 48 | lookUpBase64Alphabet[i] = (char) ('0' + j); 49 | } 50 | lookUpBase64Alphabet[62] = (char) '+'; 51 | lookUpBase64Alphabet[63] = (char) '/'; 52 | 53 | } 54 | 55 | private static boolean isWhiteSpace(char octect) { 56 | return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); 57 | } 58 | 59 | private static boolean isPad(char octect) { 60 | return (octect == PAD); 61 | } 62 | 63 | private static boolean isData(char octect) { 64 | return (octect < BASELENGTH && base64Alphabet[octect] != -1); 65 | } 66 | 67 | /** 68 | * Encodes hex octects into Base64 69 | * 70 | * @param binaryData 71 | * Array containing binaryData 72 | * @return Encoded Base64 array 73 | */ 74 | public static String encode(byte[] binaryData) { 75 | 76 | if (binaryData == null) { 77 | return null; 78 | } 79 | 80 | int lengthDataBits = binaryData.length * EIGHTBIT; 81 | if (lengthDataBits == 0) { 82 | return ""; 83 | } 84 | 85 | int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; 86 | int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; 87 | int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets; 88 | char encodedData[] = null; 89 | 90 | encodedData = new char[numberQuartet * 4]; 91 | 92 | byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; 93 | 94 | int encodedIndex = 0; 95 | int dataIndex = 0; 96 | if (fDebug) { 97 | System.out.println("number of triplets = " + numberTriplets); 98 | } 99 | 100 | for (int i = 0; i < numberTriplets; i++) { 101 | b1 = binaryData[dataIndex++]; 102 | b2 = binaryData[dataIndex++]; 103 | b3 = binaryData[dataIndex++]; 104 | 105 | if (fDebug) { 106 | System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3); 107 | } 108 | 109 | l = (byte) (b2 & 0x0f); 110 | k = (byte) (b1 & 0x03); 111 | 112 | byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); 113 | byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); 114 | byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); 115 | 116 | if (fDebug) { 117 | System.out.println("val2 = " + val2); 118 | System.out.println("k4 = " + (k << 4)); 119 | System.out.println("vak = " + (val2 | (k << 4))); 120 | } 121 | 122 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; 123 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; 124 | encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3]; 125 | encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f]; 126 | } 127 | 128 | // form integral number of 6-bit groups 129 | if (fewerThan24bits == EIGHTBIT) { 130 | b1 = binaryData[dataIndex]; 131 | k = (byte) (b1 & 0x03); 132 | if (fDebug) { 133 | System.out.println("b1=" + b1); 134 | System.out.println("b1<<2 = " + (b1 >> 2)); 135 | } 136 | byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); 137 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; 138 | encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4]; 139 | encodedData[encodedIndex++] = PAD; 140 | encodedData[encodedIndex++] = PAD; 141 | } else if (fewerThan24bits == SIXTEENBIT) { 142 | b1 = binaryData[dataIndex]; 143 | b2 = binaryData[dataIndex + 1]; 144 | l = (byte) (b2 & 0x0f); 145 | k = (byte) (b1 & 0x03); 146 | 147 | byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); 148 | byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); 149 | 150 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; 151 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; 152 | encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2]; 153 | encodedData[encodedIndex++] = PAD; 154 | } 155 | 156 | return new String(encodedData); 157 | } 158 | 159 | /** 160 | * Decodes Base64 data into octects 161 | * 162 | * @param encoded 163 | * string containing Base64 data 164 | * @return Array containind decoded data. 165 | */ 166 | public static byte[] decode(String encoded) { 167 | 168 | if (encoded == null) { 169 | return null; 170 | } 171 | 172 | char[] base64Data = encoded.toCharArray(); 173 | // remove white spaces 174 | int len = removeWhiteSpace(base64Data); 175 | 176 | if (len % FOURBYTE != 0) { 177 | return null;// should be divisible by four 178 | } 179 | 180 | int numberQuadruple = (len / FOURBYTE); 181 | 182 | if (numberQuadruple == 0) { 183 | return new byte[0]; 184 | } 185 | 186 | byte decodedData[] = null; 187 | byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; 188 | char d1 = 0, d2 = 0, d3 = 0, d4 = 0; 189 | 190 | int i = 0; 191 | int encodedIndex = 0; 192 | int dataIndex = 0; 193 | decodedData = new byte[(numberQuadruple) * 3]; 194 | 195 | for (; i < numberQuadruple - 1; i++) { 196 | 197 | if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])) 198 | || !isData((d3 = base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++]))) { 199 | return null; 200 | } // if found "no data" just return null 201 | 202 | b1 = base64Alphabet[d1]; 203 | b2 = base64Alphabet[d2]; 204 | b3 = base64Alphabet[d3]; 205 | b4 = base64Alphabet[d4]; 206 | 207 | decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); 208 | decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 209 | decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); 210 | } 211 | 212 | if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) { 213 | return null;// if found "no data" just return null 214 | } 215 | 216 | b1 = base64Alphabet[d1]; 217 | b2 = base64Alphabet[d2]; 218 | 219 | d3 = base64Data[dataIndex++]; 220 | d4 = base64Data[dataIndex++]; 221 | if (!isData((d3)) || !isData((d4))) {// Check if they are PAD characters 222 | if (isPad(d3) && isPad(d4)) { 223 | if ((b2 & 0xf) != 0)// last 4 bits should be zero 224 | { 225 | return null; 226 | } 227 | byte[] tmp = new byte[i * 3 + 1]; 228 | System.arraycopy(decodedData, 0, tmp, 0, i * 3); 229 | tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 230 | return tmp; 231 | } else if (!isPad(d3) && isPad(d4)) { 232 | b3 = base64Alphabet[d3]; 233 | if ((b3 & 0x3) != 0)// last 2 bits should be zero 234 | { 235 | return null; 236 | } 237 | byte[] tmp = new byte[i * 3 + 2]; 238 | System.arraycopy(decodedData, 0, tmp, 0, i * 3); 239 | tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); 240 | tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 241 | return tmp; 242 | } else { 243 | return null; 244 | } 245 | } else { // No PAD e.g 3cQl 246 | b3 = base64Alphabet[d3]; 247 | b4 = base64Alphabet[d4]; 248 | decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); 249 | decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 250 | decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); 251 | 252 | } 253 | 254 | return decodedData; 255 | } 256 | 257 | /** 258 | * remove WhiteSpace from MIME containing encoded Base64 data. 259 | * 260 | * @param data 261 | * the byte array of base64 data (with WS) 262 | * @return the new length 263 | */ 264 | private static int removeWhiteSpace(char[] data) { 265 | if (data == null) { 266 | return 0; 267 | } 268 | 269 | // count characters that's not whitespace 270 | int newSize = 0; 271 | int len = data.length; 272 | for (int i = 0; i < len; i++) { 273 | if (!isWhiteSpace(data[i])) { 274 | data[newSize++] = data[i]; 275 | } 276 | } 277 | return newSize; 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/encrypt/RSAEncrypt.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.encrypt; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.FileReader; 6 | import java.io.FileWriter; 7 | import java.io.IOException; 8 | import java.security.InvalidKeyException; 9 | import java.security.KeyFactory; 10 | import java.security.KeyPair; 11 | import java.security.KeyPairGenerator; 12 | import java.security.NoSuchAlgorithmException; 13 | import java.security.SecureRandom; 14 | import java.security.interfaces.RSAPrivateKey; 15 | import java.security.interfaces.RSAPublicKey; 16 | import java.security.spec.InvalidKeySpecException; 17 | import java.security.spec.PKCS8EncodedKeySpec; 18 | import java.security.spec.X509EncodedKeySpec; 19 | 20 | import javax.crypto.BadPaddingException; 21 | import javax.crypto.Cipher; 22 | import javax.crypto.IllegalBlockSizeException; 23 | import javax.crypto.NoSuchPaddingException; 24 | 25 | /** 26 | * RSA加密解密工具类 27 | * 28 | * @author taomk 2017年7月4日 下午1:46:32 29 | * 30 | */ 31 | public class RSAEncrypt { 32 | 33 | /** 34 | * 字节数据转字符串专用集合 35 | */ 36 | private static final char[] HEX_CHAR = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 37 | 'f' }; 38 | 39 | /** 40 | * 随机生成密钥对 41 | */ 42 | public static void genKeyPair(String filePath) { 43 | 44 | // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象 45 | KeyPairGenerator keyPairGen = null; 46 | try { 47 | keyPairGen = KeyPairGenerator.getInstance("RSA"); 48 | } catch (NoSuchAlgorithmException e) { 49 | e.printStackTrace(); 50 | } 51 | 52 | // 初始化密钥对生成器,密钥大小为96-1024位 53 | keyPairGen.initialize(1024, new SecureRandom()); 54 | 55 | // 生成一个密钥对,保存在keyPair中 56 | KeyPair keyPair = keyPairGen.generateKeyPair(); 57 | 58 | // 得到私钥 59 | RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); 60 | 61 | // 得到公钥 62 | RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); 63 | 64 | try { 65 | // 得到公钥字符串 66 | 67 | String publicKeyString = Base64.encode(publicKey.getEncoded()); 68 | // 得到私钥字符串 69 | String privateKeyString = Base64.encode(privateKey.getEncoded()); 70 | // 将密钥对写入到文件 71 | FileWriter pubfw = new FileWriter(filePath + "/publicKey.keystore"); 72 | FileWriter prifw = new FileWriter(filePath + "/privateKey.keystore"); 73 | BufferedWriter pubbw = new BufferedWriter(pubfw); 74 | BufferedWriter pribw = new BufferedWriter(prifw); 75 | pubbw.write(publicKeyString); 76 | pribw.write(privateKeyString); 77 | pubbw.flush(); 78 | pubbw.close(); 79 | pubfw.close(); 80 | pribw.flush(); 81 | pribw.close(); 82 | prifw.close(); 83 | } catch (Exception e) { 84 | e.printStackTrace(); 85 | } 86 | } 87 | 88 | /** 89 | * 从文件中输入流中加载公钥 90 | * 91 | * @param in 92 | * 公钥输入流 93 | * @throws Exception 94 | * 加载公钥时产生的异常 95 | */ 96 | public static String loadPublicKeyByFile(String path) throws Exception { 97 | try { 98 | BufferedReader br = new BufferedReader(new FileReader(path + "/publicKey.keystore")); 99 | String readLine = null; 100 | StringBuilder sb = new StringBuilder(); 101 | while ((readLine = br.readLine()) != null) { 102 | sb.append(readLine); 103 | } 104 | br.close(); 105 | return sb.toString(); 106 | } catch (IOException e) { 107 | throw new Exception("公钥数据流读取错误"); 108 | } catch (NullPointerException e) { 109 | throw new Exception("公钥输入流为空"); 110 | } 111 | } 112 | 113 | /** 114 | * 从字符串中加载公钥 115 | * 116 | * @param publicKeyStr 117 | * 公钥数据字符串 118 | * @throws Exception 119 | * 加载公钥时产生的异常 120 | */ 121 | public static RSAPublicKey loadPublicKeyByStr(String publicKeyStr) throws Exception { 122 | try { 123 | byte[] buffer = Base64.decode(publicKeyStr); 124 | KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 125 | X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer); 126 | return (RSAPublicKey) keyFactory.generatePublic(keySpec); 127 | } catch (NoSuchAlgorithmException e) { 128 | throw new Exception("无此算法"); 129 | } catch (InvalidKeySpecException e) { 130 | throw new Exception("公钥非法"); 131 | } catch (NullPointerException e) { 132 | throw new Exception("公钥数据为空"); 133 | } 134 | } 135 | 136 | /** 137 | * 从文件中加载私钥 138 | * 139 | * @param keyFileName 140 | * 私钥文件名 141 | * @return 是否成功 142 | * @throws Exception 143 | */ 144 | public static String loadPrivateKeyByFile(String path) throws Exception { 145 | try { 146 | BufferedReader br = new BufferedReader(new FileReader(path + "/privateKey.keystore")); 147 | String readLine = null; 148 | StringBuilder sb = new StringBuilder(); 149 | while ((readLine = br.readLine()) != null) { 150 | sb.append(readLine); 151 | } 152 | br.close(); 153 | return sb.toString(); 154 | } catch (IOException e) { 155 | throw new Exception("私钥数据读取错误"); 156 | } catch (NullPointerException e) { 157 | throw new Exception("私钥输入流为空"); 158 | } 159 | } 160 | 161 | public static RSAPrivateKey loadPrivateKeyByStr(String privateKeyStr) throws Exception { 162 | try { 163 | byte[] buffer = Base64.decode(privateKeyStr); 164 | PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer); 165 | KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 166 | return (RSAPrivateKey) keyFactory.generatePrivate(keySpec); 167 | } catch (NoSuchAlgorithmException e) { 168 | throw new Exception("无此算法"); 169 | } catch (InvalidKeySpecException e) { 170 | throw new Exception("私钥非法"); 171 | } catch (NullPointerException e) { 172 | throw new Exception("私钥数据为空"); 173 | } 174 | } 175 | 176 | /** 177 | * 公钥加密过程 178 | * 179 | * @param publicKey 180 | * 公钥 181 | * @param plainTextData 182 | * 明文数据 183 | * @return 184 | * @throws Exception 185 | * 加密过程中的异常信息 186 | */ 187 | public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData) throws Exception { 188 | if (publicKey == null) { 189 | throw new Exception("加密公钥为空, 请设置"); 190 | } 191 | Cipher cipher = null; 192 | try { 193 | // 使用默认RSA 194 | cipher = Cipher.getInstance("RSA"); 195 | // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider()); 196 | cipher.init(Cipher.ENCRYPT_MODE, publicKey); 197 | byte[] output = cipher.doFinal(plainTextData); 198 | return output; 199 | } catch (NoSuchAlgorithmException e) { 200 | throw new Exception("无此加密算法"); 201 | } catch (NoSuchPaddingException e) { 202 | e.printStackTrace(); 203 | return null; 204 | } catch (InvalidKeyException e) { 205 | throw new Exception("加密公钥非法,请检查"); 206 | } catch (IllegalBlockSizeException e) { 207 | throw new Exception("明文长度非法"); 208 | } catch (BadPaddingException e) { 209 | throw new Exception("明文数据已损坏"); 210 | } 211 | } 212 | 213 | /** 214 | * 私钥加密过程 215 | * 216 | * @param privateKey 217 | * 私钥 218 | * @param plainTextData 219 | * 明文数据 220 | * @return 221 | * @throws Exception 222 | * 加密过程中的异常信息 223 | */ 224 | public static byte[] encrypt(RSAPrivateKey privateKey, byte[] plainTextData) throws Exception { 225 | if (privateKey == null) { 226 | throw new Exception("加密私钥为空, 请设置"); 227 | } 228 | Cipher cipher = null; 229 | try { 230 | // 使用默认RSA 231 | cipher = Cipher.getInstance("RSA"); 232 | cipher.init(Cipher.ENCRYPT_MODE, privateKey); 233 | byte[] output = cipher.doFinal(plainTextData); 234 | return output; 235 | } catch (NoSuchAlgorithmException e) { 236 | throw new Exception("无此加密算法"); 237 | } catch (NoSuchPaddingException e) { 238 | e.printStackTrace(); 239 | return null; 240 | } catch (InvalidKeyException e) { 241 | throw new Exception("加密私钥非法,请检查"); 242 | } catch (IllegalBlockSizeException e) { 243 | throw new Exception("明文长度非法"); 244 | } catch (BadPaddingException e) { 245 | throw new Exception("明文数据已损坏"); 246 | } 247 | } 248 | 249 | /** 250 | * 私钥解密过程 251 | * 252 | * @param privateKey 253 | * 私钥 254 | * @param cipherData 255 | * 密文数据 256 | * @return 明文 257 | * @throws Exception 258 | * 解密过程中的异常信息 259 | */ 260 | public static byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception { 261 | if (privateKey == null) { 262 | throw new Exception("解密私钥为空, 请设置"); 263 | } 264 | Cipher cipher = null; 265 | try { 266 | // 使用默认RSA 267 | cipher = Cipher.getInstance("RSA"); 268 | // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider()); 269 | cipher.init(Cipher.DECRYPT_MODE, privateKey); 270 | byte[] output = cipher.doFinal(cipherData); 271 | return output; 272 | } catch (NoSuchAlgorithmException e) { 273 | throw new Exception("无此解密算法"); 274 | } catch (NoSuchPaddingException e) { 275 | e.printStackTrace(); 276 | return null; 277 | } catch (InvalidKeyException e) { 278 | throw new Exception("解密私钥非法,请检查"); 279 | } catch (IllegalBlockSizeException e) { 280 | throw new Exception("密文长度非法"); 281 | } catch (BadPaddingException e) { 282 | throw new Exception("密文数据已损坏"); 283 | } 284 | } 285 | 286 | /** 287 | * 公钥解密过程 288 | * 289 | * @param publicKey 290 | * 公钥 291 | * @param cipherData 292 | * 密文数据 293 | * @return 明文 294 | * @throws Exception 295 | * 解密过程中的异常信息 296 | */ 297 | public static byte[] decrypt(RSAPublicKey publicKey, byte[] cipherData) throws Exception { 298 | if (publicKey == null) { 299 | throw new Exception("解密公钥为空, 请设置"); 300 | } 301 | Cipher cipher = null; 302 | try { 303 | // 使用默认RSA 304 | cipher = Cipher.getInstance("RSA"); 305 | // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider()); 306 | cipher.init(Cipher.DECRYPT_MODE, publicKey); 307 | byte[] output = cipher.doFinal(cipherData); 308 | return output; 309 | } catch (NoSuchAlgorithmException e) { 310 | throw new Exception("无此解密算法"); 311 | } catch (NoSuchPaddingException e) { 312 | e.printStackTrace(); 313 | return null; 314 | } catch (InvalidKeyException e) { 315 | throw new Exception("解密公钥非法,请检查"); 316 | } catch (IllegalBlockSizeException e) { 317 | throw new Exception("密文长度非法"); 318 | } catch (BadPaddingException e) { 319 | throw new Exception("密文数据已损坏"); 320 | } 321 | } 322 | 323 | /** 324 | * 字节数据转十六进制字符串 325 | * 326 | * @param data 327 | * 输入数据 328 | * @return 十六进制内容 329 | */ 330 | public static String byteArrayToString(byte[] data) { 331 | StringBuilder stringBuilder = new StringBuilder(); 332 | for (int i = 0; i < data.length; i++) { 333 | // 取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移 334 | stringBuilder.append(HEX_CHAR[(data[i] & 0xf0) >>> 4]); 335 | // 取出字节的低四位 作为索引得到相应的十六进制标识符 336 | stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]); 337 | if (i < data.length - 1) { 338 | stringBuilder.append(' '); 339 | } 340 | } 341 | return stringBuilder.toString(); 342 | } 343 | } 344 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/encrypt/RSASignature.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.encrypt; 2 | 3 | import java.security.KeyFactory; 4 | import java.security.PrivateKey; 5 | import java.security.PublicKey; 6 | import java.security.spec.PKCS8EncodedKeySpec; 7 | import java.security.spec.X509EncodedKeySpec; 8 | 9 | /** 10 | * @author taomk 2017年7月4日 下午1:55:23 11 | * 12 | */ 13 | public class RSASignature { 14 | /** 15 | * 签名算法 16 | */ 17 | public static final String SIGN_ALGORITHMS = "SHA1WithRSA"; 18 | 19 | /** 20 | * RSA签名 21 | * 22 | * @param content 23 | * 待签名数据 24 | * @param privateKey 25 | * 商户私钥 26 | * @param encode 27 | * 字符集编码 28 | * @return 签名值 29 | */ 30 | public static String sign(String content, String privateKey, String encode) { 31 | try { 32 | PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decode(privateKey)); 33 | 34 | KeyFactory keyf = KeyFactory.getInstance("RSA"); 35 | PrivateKey priKey = keyf.generatePrivate(priPKCS8); 36 | 37 | java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS); 38 | 39 | signature.initSign(priKey); 40 | signature.update(content.getBytes(encode)); 41 | 42 | byte[] signed = signature.sign(); 43 | 44 | return Base64.encode(signed).toString(); 45 | } catch (Exception e) { 46 | e.printStackTrace(); 47 | } 48 | 49 | return null; 50 | } 51 | 52 | /** 53 | * 通过私钥对加密对象加签 54 | * @param content 55 | * @param privateKey 56 | * @return 57 | */ 58 | public static String sign(String content, String privateKey) { 59 | try { 60 | PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decode(privateKey)); 61 | KeyFactory keyf = KeyFactory.getInstance("RSA"); 62 | PrivateKey priKey = keyf.generatePrivate(priPKCS8); 63 | java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS); 64 | signature.initSign(priKey); 65 | signature.update(content.getBytes()); 66 | byte[] signed = signature.sign(); 67 | return Base64.encode(signed).toString(); 68 | } catch (Exception e) { 69 | e.printStackTrace(); 70 | } 71 | return null; 72 | } 73 | 74 | /** 75 | * RSA验签名检查 76 | * 77 | * @param content 78 | * 待签名数据 79 | * @param sign 80 | * 签名值 81 | * @param publicKey 82 | * 分配给开发商公钥 83 | * @param encode 84 | * 字符集编码 85 | * @return 布尔值 86 | */ 87 | public static boolean doCheck(String content, String sign, String publicKey, String encode) { 88 | try { 89 | KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 90 | byte[] encodedKey = Base64.decode(publicKey); 91 | PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey)); 92 | 93 | java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS); 94 | 95 | signature.initVerify(pubKey); 96 | signature.update(content.getBytes(encode)); 97 | 98 | boolean bverify = signature.verify(Base64.decode(sign)); 99 | return bverify; 100 | 101 | } catch (Exception e) { 102 | e.printStackTrace(); 103 | } 104 | 105 | return false; 106 | } 107 | 108 | public static boolean doCheck(String content, String sign, String publicKey) { 109 | try { 110 | KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 111 | byte[] encodedKey = Base64.decode(publicKey); 112 | PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey)); 113 | 114 | java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS); 115 | 116 | signature.initVerify(pubKey); 117 | signature.update(content.getBytes()); 118 | 119 | boolean bverify = signature.verify(Base64.decode(sign)); 120 | return bverify; 121 | 122 | } catch (Exception e) { 123 | e.printStackTrace(); 124 | } 125 | 126 | return false; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/encrypt/Test.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.encrypt; 2 | 3 | /** 4 | * @author taomk 2017年7月4日 下午7:02:05 5 | * 6 | */ 7 | public class Test { 8 | 9 | public static void main(String[] args) throws Exception { 10 | 11 | String filepath = "/Users/Dev/tmp/"; 12 | 13 | System.out.println("--------------生成公钥和私钥过程-------------------"); 14 | // 生成公钥和私钥 15 | RSAEncrypt.genKeyPair(filepath); 16 | System.out.println("生成密钥对成功,保存路径为:" + filepath); 17 | System.out.println(); 18 | 19 | System.out.println("--------------公钥加密私钥解密过程-------------------"); 20 | String plainText = "taomk_公钥加密私钥解密"; 21 | // 公钥加密过程 22 | byte[] cipherData = RSAEncrypt.encrypt(RSAEncrypt.loadPublicKeyByStr(RSAEncrypt.loadPublicKeyByFile(filepath)), 23 | plainText.getBytes()); 24 | String cipher = Base64.encode(cipherData).toString(); 25 | // 私钥解密过程 26 | byte[] res = RSAEncrypt.decrypt(RSAEncrypt.loadPrivateKeyByStr(RSAEncrypt.loadPrivateKeyByFile(filepath)), 27 | Base64.decode(cipher)); 28 | String restr = new String(res); 29 | System.out.println("原文:" + plainText); 30 | System.out.println("加密:" + cipher); 31 | System.out.println("解密:" + restr); 32 | System.out.println(); 33 | 34 | System.out.println("--------------私钥加密公钥解密过程-------------------"); 35 | plainText = "taomk_私钥加密公钥解密"; 36 | // 私钥加密过程 37 | cipherData = RSAEncrypt.encrypt(RSAEncrypt.loadPrivateKeyByStr(RSAEncrypt.loadPrivateKeyByFile(filepath)), 38 | plainText.getBytes()); 39 | cipher = Base64.encode(cipherData).toString(); 40 | // 公钥解密过程 41 | res = RSAEncrypt.decrypt(RSAEncrypt.loadPublicKeyByStr(RSAEncrypt.loadPublicKeyByFile(filepath)), 42 | Base64.decode(cipher)); 43 | restr = new String(res); 44 | System.out.println("原文:" + plainText); 45 | System.out.println("加密:" + cipher); 46 | System.out.println("解密:" + restr); 47 | System.out.println(); 48 | 49 | System.out.println("---------------私钥签名过程------------------"); 50 | String content = "taomk_这是用于签名的原始数据"; 51 | String signstr = RSASignature.sign(content, RSAEncrypt.loadPrivateKeyByFile(filepath)); 52 | System.out.println("签名原串:" + content); 53 | System.out.println("签名串:" + signstr); 54 | System.out.println(); 55 | 56 | System.out.println("---------------公钥校验签名------------------"); 57 | System.out.println("签名原串:" + content); 58 | System.out.println("签名串:" + signstr); 59 | 60 | System.out.println("验签结果:" + RSASignature.doCheck(content, signstr, RSAEncrypt.loadPublicKeyByFile(filepath))); 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/forfun/HelloWorld.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.forfun; 2 | 3 | import java.util.Random; 4 | 5 | /** 6 | * Random传入seed,伪随机 7 | * @author taomk 2017年6月19日 上午11:12:39 8 | * 9 | */ 10 | public class HelloWorld { 11 | 12 | public static void main(String... args) { 13 | System.out.println(randomString(-229985452) + ' ' + randomString(-147909649)); 14 | } 15 | 16 | public static String randomString(int seed) { 17 | Random rand = new Random(seed); 18 | StringBuilder sb = new StringBuilder(); 19 | while (true) { 20 | int n = rand.nextInt(27); 21 | if (n == 0) 22 | break; 23 | sb.append((char) ('`' + n)); 24 | } 25 | return sb.toString(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/forfun/Test.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.forfun; 2 | 3 | /** 4 | * @author taomk 2017年6月19日 下午9:04:45 5 | * 6 | */ 7 | public class Test { 8 | 9 | public static void main(String[] args) { 10 | 11 | String a = "123"; 12 | change(a); 13 | System.out.println(a); 14 | 15 | int c = 123; 16 | change(c); 17 | System.out.println(c); 18 | 19 | Student s = new Student(); 20 | s.setName("Tom"); 21 | s.setAge(18); 22 | change(s); 23 | System.out.println(s); 24 | } 25 | 26 | public static String change(String target){ 27 | target = "welcome"; 28 | return target; 29 | } 30 | 31 | public static int change(int target){ 32 | target = 233; 33 | return target; 34 | } 35 | 36 | public static Student change(Student target){ 37 | target.setName("Bob"); 38 | target.setAge(20); 39 | return target; 40 | } 41 | } 42 | 43 | class Student{ 44 | 45 | String name; 46 | int age; 47 | 48 | public String getName() { 49 | return name; 50 | } 51 | public void setName(String name) { 52 | this.name = name; 53 | } 54 | public int getAge() { 55 | return age; 56 | } 57 | public void setAge(int age) { 58 | this.age = age; 59 | } 60 | @Override 61 | public String toString() { 62 | return "Student [name=" + name + ", age=" + age + "]"; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/gc/Allocation.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.gc; 2 | 3 | /** 4 | *
 5 |  * 验证:对象优先在Eden分配
 6 |  * 	
 7 |  * VM Args:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8
 8 |  * 
9 | * 10 | * @author taomk 2016年11月24日 下午6:15:46 11 | * 12 | */ 13 | public class Allocation { 14 | 15 | private static final int _1MB = 1024*1024; 16 | 17 | /** 18 | * 尝试分配了3个2MB大小和一个4MB大小的对象, 19 | * 在运行时通过-Xms20M、-Xmx20M和-Xmn10M这三个参数限制Java堆大小为20MB,且不可扩展。 20 | * 其中10MB分配给新生代,剩下的10MB分配给老生代。 21 | * -XX:SurvivorRatio=8决定了新生代中Eden区与一个Survivor区的空间大小比例为8:1, 22 | * 23 | * @param args 24 | */ 25 | @SuppressWarnings("unused") 26 | public static void main(String[] args) { 27 | byte[] allocation1 , allocation2, allocation3, allocation4; 28 | allocation1 = new byte[2*_1MB]; 29 | allocation2 = new byte[2*_1MB]; 30 | allocation3 = new byte[2*_1MB]; 31 | allocation4 = new byte[4*_1MB];// 出现一次Minor GC 32 | 33 | /** 34 | * 35 | * 36 | */ 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/gc/FinalizeEscapeGC.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.gc; 2 | 3 | /** 4 | *
 5 |  * 一个对象自我拯救的演示
 6 |  * 此代码演示了两点:
 7 |  * 1,对象可以在被GC时自我拯救
 8 |  * 2,这种自救的机会只有一次,因为一个对象的finalize()方法只能被系统自动调用一次
 9 |  * 
10 | * 11 | * @author taomk 2016年11月14日 下午4:33:28 12 | * 13 | */ 14 | public class FinalizeEscapeGC { 15 | 16 | public static FinalizeEscapeGC SAVE_HOOK = null; 17 | 18 | public void isAlive(){ 19 | System.out.println("yes , i am still alive. :)"); 20 | } 21 | 22 | @Override 23 | protected void finalize() throws Throwable{ 24 | super.finalize(); 25 | System.out.println("finalize() method exexuted!"); 26 | FinalizeEscapeGC.SAVE_HOOK = this; 27 | } 28 | 29 | public static void main(String[] args) throws Throwable { 30 | SAVE_HOOK = new FinalizeEscapeGC(); 31 | 32 | // 对象第一次拯救自己成功 33 | SAVE_HOOK = null; 34 | System.gc(); 35 | // 因为finalize()方法的优先级较低,所有等待500毫秒 36 | Thread.sleep(500L); 37 | 38 | if(SAVE_HOOK != null){ 39 | SAVE_HOOK.isAlive(); 40 | }else{ 41 | System.out.println("no , i am dead. :("); 42 | } 43 | 44 | // 对象第二次执行和以上部分相同的代码,但是却自救失败 45 | SAVE_HOOK = null; 46 | System.gc(); 47 | // 因为finalize()方法的优先级较低,所有等待500毫秒 48 | Thread.sleep(500L); 49 | 50 | if(SAVE_HOOK != null){ 51 | SAVE_HOOK.isAlive(); 52 | }else{ 53 | System.out.println("no , i am dead. :("); 54 | } 55 | 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/gc/ReferenceCountingGC.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.gc; 2 | 3 | /** 4 | *
 5 |  * 引用计数算法的缺陷是不能很好的解决对象之间循环引用的问题。
 6 |  * 示例代码证明了,虚拟机并不是采用引用计数算法来判断对象是否存活的。
 7 |  * 
8 | * @author taomk 2016年11月8日 下午7:46:53 9 | * 10 | */ 11 | public class ReferenceCountingGC { 12 | 13 | public Object instance = null; 14 | 15 | private static final int _1MB = 1024*1024; 16 | 17 | // 这个成员属性的唯一意义就是占点内存,以便在GC日志中能清楚是否被回收过 18 | @SuppressWarnings("unused") 19 | private byte[] bigsize = new byte[2*_1MB]; 20 | 21 | public static void main(String[] args) { 22 | 23 | ReferenceCountingGC objA = new ReferenceCountingGC(); 24 | ReferenceCountingGC objB = new ReferenceCountingGC(); 25 | objA.instance = objB; 26 | objB.instance = objA; 27 | 28 | objA = null; 29 | objB = null; 30 | 31 | // 执行GC 32 | System.gc(); 33 | 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/hashcode/HashCodeAndEquals.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.hashcode; 2 | 3 | import java.util.HashMap; 4 | import java.util.HashSet; 5 | import java.util.Iterator; 6 | import java.util.Map; 7 | import java.util.Set; 8 | 9 | /** 10 | * @author taomk 2017年7月6日 下午11:10:31 11 | * 12 | */ 13 | public class HashCodeAndEquals { 14 | 15 | public static void main(String[] args) { 16 | 17 | Student s1 = new Student("1001", "小红", 12, "Beijing"); 18 | Student s2 = new Student("1002", "小明", 12, "Harbin"); 19 | Student s3 = new Student("1003", "小强", 13, "Tianjin"); 20 | Student s4 = new Student("1001", "小花", 13, "HongKong"); 21 | 22 | Set students = new HashSet(); 23 | students.add(s1); 24 | students.add(s2); 25 | students.add(s3); 26 | students.add(s4); 27 | 28 | for (Student student : students) { 29 | System.out.println(student); 30 | } 31 | 32 | // Student类没有重写hashCode()方法,导致原本相等的两个对象(s1、s3)都放入了集合中 33 | 34 | 35 | System.out.println("______________________"); 36 | 37 | Map studentMap = new HashMap(); 38 | studentMap.put(s1, "s1"); 39 | studentMap.put(s2, "s2"); 40 | studentMap.put(s3, "s3"); 41 | studentMap.put(s4, "s4"); 42 | 43 | Iterator iter = studentMap.keySet().iterator(); 44 | while(iter.hasNext()){ 45 | Student student = iter.next(); 46 | System.out.println(student + " -> " + studentMap.get(student)); 47 | } 48 | } 49 | 50 | } 51 | 52 | class Student { 53 | 54 | // 属性定义 55 | private String number; 56 | private String name; 57 | private int age; 58 | private String address; 59 | 60 | // 构造函数 61 | public Student(String number, String name, int age, String address) { 62 | super(); 63 | this.number = number; 64 | this.name = name; 65 | this.age = age; 66 | this.address = address; 67 | } 68 | 69 | // 省略getter、setter 70 | 71 | @Override 72 | public String toString() { 73 | return "Student [number=" + number + ", name=" + name + ", age=" + age + ", address=" + address + "]"; 74 | } 75 | 76 | @Override 77 | public boolean equals(Object obj) { 78 | if (obj == null || !(obj instanceof Student)) { 79 | return false; 80 | } 81 | 82 | Student otherStudent = (Student) obj; 83 | return this.number.equals(otherStudent.number); 84 | } 85 | } -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/innerClass/Outter.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.innerClass; 2 | 3 | /** 4 | * @author taomk 2017年7月30日 下午5:02:40 5 | * 6 | */ 7 | public class Outter { 8 | 9 | class Inner { 10 | } 11 | 12 | public static void foo() { 13 | // No enclosing instance of type Outter is accessible. Must qualify the allocation with an enclosing instance of type Outter (e.g. x.new A() where x is an instance of Outter). 14 | // new Inner(); 15 | } 16 | 17 | public static void main(String[] args) { 18 | // No enclosing instance of type Outter is accessible. Must qualify the allocation with an enclosing instance of type Outter (e.g. x.new A() where x is an instance of Outter). 19 | // new Inner(); 20 | new Outter().new Inner(); 21 | } 22 | 23 | public void bar() { 24 | new Inner(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/interview/InterfaceWhitDefaultMethod.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.interview; 2 | 3 | /** 4 | * 带有默认方法的接口 5 | * 6 | * @author taomk 2017年4月6日 下午1:34:03 7 | * 8 | */ 9 | public interface InterfaceWhitDefaultMethod { 10 | 11 | String a = "test"; 12 | 13 | default void sayHi(){ 14 | System.out.println("InterfaceWhitDefaultMethod says : 'Hi!'"); 15 | } 16 | 17 | default void sayBye(){ 18 | System.out.println("InterfaceWhitDefaultMethod says : 'Bye!'"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/interview/InterfaceWhitDefaultMethodImpl.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.interview; 2 | 3 | /** 4 | * @author taomk 2017年4月6日 下午1:36:23 5 | * 6 | */ 7 | public class InterfaceWhitDefaultMethodImpl implements InterfaceWhitDefaultMethod { 8 | 9 | public static void main(String[] args) { 10 | InterfaceWhitDefaultMethod interfaceInstance = new InterfaceWhitDefaultMethodImpl(); 11 | interfaceInstance.sayBye(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/interview/ReverseSingleLinkedNode.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.interview; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * 搜狐面试时提出的一个问题:倒序排列给出的单链表 7 | * 8 | * @author taomk 2017年3月29日 下午3:39:55 9 | * 10 | */ 11 | public class ReverseSingleLinkedNode { 12 | 13 | public static void main(String[] args) { 14 | 15 | // 初始状态 16 | SingleLinkedNode singleLinked = new SingleLinkedNode(0); 17 | for (int i = 1; i <= 5; i++) { 18 | singleLinked.add(i); 19 | } 20 | 21 | System.out.print("init\t: "); 22 | SingleLinkedNode.show(singleLinked); 23 | 24 | // insert 25 | singleLinked.insert(6, 6); 26 | 27 | System.out.print("\ninsert\t: "); 28 | SingleLinkedNode.show(singleLinked); 29 | 30 | 31 | // delete 32 | singleLinked.delete(6); 33 | System.out.print("\ndelete\t: "); 34 | SingleLinkedNode.show(singleLinked); 35 | 36 | // reverse 37 | 38 | System.out.print("\nreverse\t: "); 39 | // Node reversedNode = Node.reverseByStack(singleLinked.getHead()); 40 | Node reversedNode = Node.reverseByExchange(singleLinked.getHead()); 41 | Node.show(reversedNode); 42 | } 43 | 44 | } 45 | 46 | /** 47 | * 单链表实现 48 | * 49 | * @author taomk 2017年3月29日 下午6:10:54 50 | * 51 | */ 52 | class SingleLinkedNode{ 53 | 54 | /** 55 | * 头节点、尾节点 56 | */ 57 | private Node head , tail; 58 | 59 | SingleLinkedNode(Object data){ 60 | 61 | tail = head = new Node(data); 62 | } 63 | 64 | 65 | /** 66 | * 将指定值构造成一个节点,并添加在链表尾部 67 | * @param data 68 | */ 69 | public void add(Object data){ 70 | Node newNode = new Node(data); 71 | if(head == null){ 72 | head = newNode; 73 | }else{ 74 | tail.setNext(newNode); 75 | } 76 | tail = newNode; 77 | } 78 | 79 | /** 80 | * 将指定节点添加在链表尾部 81 | * @param data 82 | */ 83 | public void add(Node newNode){ 84 | if(head == null){ 85 | head = newNode; 86 | }else{ 87 | tail.setNext(newNode); 88 | } 89 | tail = newNode; 90 | } 91 | 92 | 93 | /** 94 | * 将代表指定值的节点插入到指定的index位置 95 | * @param index 96 | * @param data 97 | */ 98 | public void insert(int index, Object data){ 99 | 100 | // 遍历查找出位置为index-1的那个节点,即为将要插入节点的前一个节点 101 | Node aheadNode = head; 102 | int aheadIndex = 0; 103 | while(aheadNode!=null && aheadIndex "); 145 | } 146 | current = current.getNext(); 147 | } 148 | } 149 | 150 | public Node getHead() { 151 | return head; 152 | } 153 | 154 | public void setHead(Node head) { 155 | this.head = head; 156 | } 157 | 158 | public Node getTail() { 159 | return tail; 160 | } 161 | 162 | public void setTail(Node tail) { 163 | this.tail = tail; 164 | } 165 | } 166 | 167 | 168 | /** 169 | * 节点定义 170 | * 171 | * @author taomk 2017年3月29日 下午4:56:08 172 | * 173 | */ 174 | class Node { 175 | 176 | /** 177 | * 节点数据 178 | */ 179 | private Object data; 180 | 181 | 182 | /** 183 | * 下一个节点 184 | */ 185 | private Node next; 186 | 187 | Node(Object value) { 188 | this.data = value; 189 | this.next = null; 190 | } 191 | 192 | public Object getData() { 193 | return data.toString(); 194 | } 195 | 196 | public void setData(int data) { 197 | this.data = data; 198 | } 199 | 200 | public Node getNext() { 201 | return next; 202 | } 203 | 204 | public void setNext(Node next) { 205 | this.next = next; 206 | } 207 | 208 | /** 209 | * 使用栈来完成链表反转 210 | * 211 | * @param head 212 | * @return 213 | */ 214 | public static Node reverseByStack(Node head) { 215 | Stack stack = new Stack(); 216 | 217 | // put all the nodes into the stack 218 | while (head != null) { 219 | stack.add(head); 220 | head = head.getNext(); 221 | } 222 | 223 | //reverse the linked list 224 | Node current = stack.pop(); 225 | head = current; 226 | while (stack.empty() != true) { 227 | Node next = stack.pop(); 228 | //set the pointer to null, so the last node will not point to the first node. 229 | next.setNext(null); 230 | current.setNext(next); 231 | current = next; 232 | } 233 | 234 | return head; 235 | } 236 | 237 | /** 238 | *
239 | 	 * 利用两个指针,分别指向前一个节点和当前节点
240 | 	 * 每次做完当前节点和下一个节点的反转后,把两个节点往下移,直到到达最后节点。
241 | 	 * 
242 | 	 * 初始链表:A(head)->B->C->D
243 | 	 * 新的链表:null(previous)
244 | 	 * 
245 | 	 * 第一次遍历:
246 | 	 * 初始链表:B(head)->C->D
247 | 	 * 新的链表:A(previous)
248 | 	 * 
249 | 	 * 第二次遍历:
250 | 	 * 初始链表:C(head)->D
251 | 	 * 新的链表:B(previous)->A
252 | 	 * 
253 | 	 * 第三次遍历:
254 | 	 * 初始链表:D(head)
255 | 	 * 新的链表:C(previous)->B->A
256 | 	 * 
257 | 	 * 第四次遍历:
258 | 	 * 初始链表:null(head)
259 | 	 * 新的链表:D(previous)->C->B->A
260 | 	 * 
261 | 	 * 
262 | * 263 | * @param head 初始链表头 264 | * @return 反转后的新链表头节点 265 | */ 266 | public static Node reverseByExchange(Node head) { 267 | Node previous = null; 268 | 269 | while (head != null) { 270 | Node nextNode = head.getNext(); 271 | head.setNext(previous); 272 | previous = head; 273 | head = nextNode; 274 | } 275 | 276 | return previous; 277 | } 278 | 279 | 280 | public static void show(Node head){ 281 | Node current = head; 282 | while(current != null){ 283 | System.out.print(current.getData()); 284 | if(current.getNext()!=null){ 285 | System.out.print(" -> "); 286 | } 287 | current = current.getNext(); 288 | } 289 | } 290 | } -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/interview/SortedByValueMapDemo.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.interview; 2 | 3 | import java.util.Collections; 4 | import java.util.Comparator; 5 | import java.util.HashMap; 6 | import java.util.LinkedHashMap; 7 | import java.util.LinkedList; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.Map.Entry; 11 | 12 | /** 13 | * 蚂蚁金服面试时提的一个问题:将Map中的value进行排序 14 | * 15 | * @author taomk 2017年3月26日 下午10:22:45 16 | * 17 | */ 18 | public class SortedByValueMapDemo { 19 | 20 | public static void main(String[] args) { 21 | 22 | Map buzObjMap = new HashMap(); 23 | buzObjMap.put("LA-1", new BuzObj(8, "Kobe")); 24 | buzObjMap.put("LA-2", new BuzObj(34, "Shaq")); 25 | buzObjMap.put("LA-3", new BuzObj(13, "Nash")); 26 | buzObjMap.put("SA-1", new BuzObj(2, "Leonard")); 27 | buzObjMap.put("SA-2", new BuzObj(8, "Parker")); 28 | buzObjMap.put("SA-3", new BuzObj(20, "Manu")); 29 | buzObjMap.put("SA-4", new BuzObj(21, "Duncan")); 30 | 31 | System.out.println("初始状态:\n" + buzObjMap); 32 | 33 | Map result = sort(buzObjMap); 34 | 35 | System.out.println("排序之后:\n" + result); 36 | } 37 | 38 | static Map sort(Map buzObjMap){ 39 | List> entryList = new LinkedList>(buzObjMap.entrySet()); 40 | Collections.sort(entryList, new Comparator>() { 41 | 42 | @Override 43 | public int compare(Map.Entry o1 , Map.Entry o2){ 44 | return o1.getValue().compareTo(o2.getValue()); 45 | } 46 | }); 47 | 48 | Map result = new LinkedHashMap(); 49 | for (Entry entry : entryList) { 50 | result.put(entry.getKey(), entry.getValue()); 51 | } 52 | 53 | return result; 54 | } 55 | 56 | } 57 | 58 | /** 59 | * 待比较的业务对象 60 | * 61 | * @author taomk 2017年3月26日 下午10:28:15 62 | * 63 | */ 64 | class BuzObj implements Comparable{ 65 | 66 | private Integer number; 67 | private String name; 68 | 69 | public BuzObj(Integer number, String name) { 70 | super(); 71 | this.number = number; 72 | this.name = name; 73 | } 74 | 75 | @Override 76 | public String toString() { 77 | return "\t BuzObj [number=" + number + ", name=" + name + "]\n"; 78 | } 79 | 80 | @Override 81 | public int compareTo(BuzObj o) { 82 | 83 | return this.number - o.number; 84 | 85 | } 86 | } -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/java8/lambda/ComparatorFactory.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.java8.lambda; 2 | 3 | import java.io.Serializable; 4 | import java.util.Comparator; 5 | 6 | /** 7 | * 函数接口可以用作方法的返回值 8 | * 9 | * @author taomk 2017年6月19日 下午1:41:56 10 | * 11 | */ 12 | public class ComparatorFactory { 13 | 14 | /** 15 | * @return lambda表达式 16 | */ 17 | public Comparator makeComparator(){ 18 | // 认为作为返回结果的Comparator 实例对象也是Serializable类型的。 19 | // Serializable接口也可以称作ZAM类型(ZAM即Zero Abstract Methods)。 20 | return (Comparator & Serializable)Integer::compareUnsigned; 21 | } 22 | 23 | public static void main(String[] args) { 24 | Comparator com = new ComparatorFactory().makeComparator(); 25 | System.out.println(com.compare(233, -332)); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/java8/lambda/defaultMethod/DefaultMethod.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.java8.lambda.defaultMethod; 2 | 3 | import java.util.LinkedList; 4 | import java.util.List; 5 | 6 | /** 7 | *
 8 |  * http://blog.csdn.net/wwwsssaaaddd/article/details/24213525
 9 |  * 
10 | * 11 | * @author taomk 2017年6月19日 下午2:30:21 12 | * 13 | */ 14 | public class DefaultMethod { 15 | 16 | public static void main(String[] args) { 17 | 18 | // init 19 | List list = new LinkedList(); 20 | list.add("Kobe"); 21 | list.add("Duncan"); 22 | list.add("Iverson"); 23 | list.add("James"); 24 | 25 | // forEach方法使用函数接口java.util.function.Consumer作为参数, 26 | // 该参数使我们能传递一个Lambda表达式或者方法引用到forEach中 27 | list.forEach(System.out::println); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/java8/lambda/principle/Principle$Action.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/src/com/taomk/understandingJVM/java8/lambda/principle/Principle$Action.class -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/java8/lambda/principle/Principle.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maokuntao/understandingJVM/c550ddd277363e343adb0ad345abcbe48974b232/src/com/taomk/understandingJVM/java8/lambda/principle/Principle.class -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/java8/lambda/principle/Principle.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.java8.lambda.principle; 2 | 3 | /** 4 | *
 5 |  * Lambda表达式背后的原理:
 6 |  * 	http://blog.csdn.net/wwwsssaaaddd/article/details/24212693
 7 |  * 
 8 |  * 
9 | * 10 | * 11 | * 12 | * @author taomk 2017年6月19日 下午1:58:29 13 | * 14 | */ 15 | public class Principle { 16 | 17 | @FunctionalInterface 18 | interface Action{ 19 | void run(String target); 20 | } 21 | 22 | public void action(Action target){ 23 | target.run("_"); 24 | } 25 | 26 | public static void main(String[] args) { 27 | new Principle().action(s -> System.out.println("^" + s + "^")); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/java8/stream/StreamTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.java8.stream; 2 | 3 | import java.util.Random; 4 | import java.util.stream.IntStream; 5 | 6 | /** 7 | * 8 | *
http://blog.csdn.net/wwwsssaaaddd/article/details/24214219
9 | * @author taomk 2017年6月19日 下午3:01:30 10 | * 11 | */ 12 | public class StreamTest { 13 | 14 | public static void main(String[] args) { 15 | 16 | IntStream range =IntStream.range(0, 50).limit(10); 17 | range.forEach(System.out::println); 18 | 19 | System.out.println("_________________________________\n"); 20 | 21 | new Random() 22 | .ints()// 随机生成一条的整数数据流 23 | .limit(10)// 我们只要10个随机整数 24 | .forEach(System.out::println); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/jcf/ArraysTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.jcf; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | /** 7 | * https://zhuanlan.zhihu.com/p/26019955 8 | * 9 | * @author taomk 2017年8月3日 下午3:48:22 10 | * 11 | */ 12 | public class ArraysTest { 13 | 14 | public static void main(String[] args) { 15 | 16 | // 将一个字符串转换为ArrayList 17 | String str1 = "abc"; 18 | String str2 = "def"; 19 | String str3 = "ghi"; 20 | String str4 = "jkl"; 21 | List strList = Arrays.asList(str1, str2, str3, str4); 22 | 23 | System.out.println(strList.getClass()); 24 | strList.forEach(s -> System.out.printf(s + "|")); 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/jcf/PerformanceTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.jcf; 2 | 3 | /** 4 | * http://www.cnblogs.com/xrq730/p/5005347.html 5 | * 6 | * @author taomk 2017年8月3日 下午6:46:36 7 | * 8 | */ 9 | public class PerformanceTest { 10 | 11 | /** 12 | * @param args 13 | */ 14 | public static void main(String[] args) { 15 | 16 | System.out.println("Hi~"); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/jmm/OOMMock.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.jmm; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * OutOfMemoryError mock 8 | * @see http://www.cnblogs.com/paddix/p/5309550.html 9 | * @author taomk 2017年5月7日 下午10:08:16 10 | * 11 | */ 12 | public class OOMMock { 13 | 14 | public static void main(String[] args) { 15 | 16 | List list = new ArrayList(); 17 | int loopCount = 0; 18 | boolean flag = true; 19 | while(flag){ 20 | try { 21 | // 每次申请1M内存 22 | list.add(new byte[1024*1024]); 23 | loopCount++; 24 | } catch (Throwable e) { 25 | e.printStackTrace(); 26 | flag = false; 27 | // 结果与设定的堆内存大小有关,不是固定的 28 | System.out.println("Count : " + loopCount); 29 | } 30 | } 31 | 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/jmm/StackErrorMock.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.jmm; 2 | 3 | /** 4 | * 测试方法(栈帧允许的调用深度) 5 | * 6 | * @see http://www.cnblogs.com/paddix/p/5309550.html 7 | * 8 | * @author taomk 2017年5月7日 下午10:00:05 9 | * 10 | */ 11 | public class StackErrorMock { 12 | 13 | private static int loopCount = 1; 14 | 15 | private void call() { 16 | loopCount++; 17 | // 递归调用 18 | call(); 19 | } 20 | 21 | public static void main(String[] args) { 22 | 23 | StackErrorMock mock = new StackErrorMock(); 24 | try { 25 | mock.call(); 26 | } catch (Throwable e) {// catch的不是Error,而是Throwable 27 | // 每次运行的结果不一样 28 | System.out.println("Stack deep : " + loopCount); 29 | e.printStackTrace(); 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/jmm/StringOOMMock.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.jmm; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * String OOM Mock 8 | * @see http://www.cnblogs.com/paddix/p/5309550.html 9 | * 10 | * @author taomk 2017年5月7日 下午10:34:49 11 | * 12 | */ 13 | public class StringOOMMock { 14 | 15 | // 不会出现JDK6中“PermGen Space”的错误信息,而是“Java heap space” 16 | // 说明在JDK8(本机Java版本是JDK8)中,字符串常量池是存放在堆(heap)中,其实JDK7也是 17 | public static void main(String[] args) { 18 | String base = "String"; 19 | List list = new ArrayList(); 20 | for (int i = 0; i < Integer.MAX_VALUE; i++) { 21 | String temp = base+base; 22 | base = temp; 23 | list.add(temp.intern()); 24 | } 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/keyworld/CheesyCounter.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.keyworld; 2 | 3 | /** 4 | *
 5 |  * volatile关键字学习:
 6 |  * {@link https://www.ibm.com/developerworks/cn/java/j-jtp06197.html}
 7 |  * 
8 | * 9 | * @author taomk 2017年5月25日 下午10:07:42 10 | * 11 | */ 12 | public class CheesyCounter { 13 | 14 | // 使用volatile来修饰count,保证count的可见性 15 | private volatile int count; 16 | 17 | // 因为count的可见性保证了每次取得的值都是最新的,所以测出不用加锁 18 | public int getCount() { 19 | return this.count; 20 | } 21 | 22 | // 因为 count++ 操作并非一个原子操作,所以使用 synchronized 关键字来保证自增的原子和可见性 23 | public synchronized void increment() { 24 | this.count++; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/keyworld/CloneStudy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.keyworld; 2 | 3 | /** 4 | * clone() 关键字研究 5 | * 6 | * @author taomk 2017年2月26日 下午8:50:44 7 | * 8 | */ 9 | public class CloneStudy implements Cloneable{ 10 | 11 | private String name; 12 | private String[] address; 13 | 14 | CloneStudy(String name ){ 15 | this.name = name; 16 | this.address = new String[2]; 17 | } 18 | 19 | 20 | public static void main(String[] args) { 21 | 22 | CloneStudy a = new CloneStudy("Kobe"); 23 | a.address[0] = "LA"; 24 | a.address[1] = "LA"; 25 | 26 | CloneStudy b = (CloneStudy) a.clone(); 27 | b.name = "James"; 28 | b.address[0] = "CL"; 29 | b.address[1] = "Miami"; 30 | 31 | // b = a; 32 | // b.name = "James"; 33 | 34 | System.out.println(a.name + " : " + a.address[0] + " & " + a.address[1]); 35 | System.out.println(b.name + " : " + b.address[0] + " & " + b.address[1]); 36 | } 37 | 38 | @Override 39 | public Object clone(){ 40 | CloneStudy cs = null; 41 | try { 42 | cs = (CloneStudy) super.clone(); //浅度clone 43 | cs.address = address.clone();//深度clone,存在更为复杂的成员变量时,如Vector等存储对象地址的容器时,就必须clone彻底。 44 | } catch (CloneNotSupportedException e) { 45 | e.printStackTrace(); 46 | } 47 | return cs; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/keyworld/VolatileStudy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.keyworld; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | 5 | /** 6 | * volatile 关键字研究 7 | * @author taomk 2017年2月25日 下午2:59:17 8 | * 9 | */ 10 | public class VolatileStudy { 11 | 12 | /** 13 | * 启动线程数量 14 | */ 15 | private static final int THREAD_COUNT = 10*100*1000; 16 | 17 | /** 18 | * 线程操作目标,每个线程都会使value值加1,TODO 1,试一试添加volatile前后区别 19 | */ 20 | private static /* volatile */ int value; 21 | 22 | /** 23 | * 使用CountDownLatch来完成并发控制,TODO 2,试一试不使用CountDownLatch的区别 24 | */ 25 | private static CountDownLatch countDownLatch = new CountDownLatch(THREAD_COUNT); 26 | 27 | public static void main(String[] args) { 28 | for (int i = 0; i < THREAD_COUNT; i++) { 29 | new Thread(){ 30 | @Override 31 | public void run() { 32 | increment(); 33 | countDownLatch.countDown(); 34 | } 35 | }.start(); 36 | } 37 | try { 38 | countDownLatch.await(); 39 | System.out.println(getValue()); 40 | } catch (InterruptedException e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | 45 | /** 46 | * value值加1,value++; 本身并不是原子操作,TODO,试试加上synchronized前后区别 47 | * @return 48 | */ 49 | public static /* synchronized */ int increment(){ 50 | return value++; 51 | } 52 | 53 | public static int getValue(){ 54 | return value; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/keyworld/sync/StringThread.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.keyworld.sync; 2 | 3 | /** 4 | * synchronized 关键字学习-String作为lock
5 | * 6 | * 7 | * http://www.cnblogs.com/xrq730/p/6662232.html 8 | * 9 | * 10 | * @author taomk 2017年4月18日 下午2:04:30 11 | * 12 | */ 13 | public class StringThread implements Runnable { 14 | 15 | /** 16 | * 锁的前缀 17 | */ 18 | private static final String PREFFIX = "LOCK_"; 19 | 20 | /** 21 | * 需要加锁的IP 22 | */ 23 | private String ip; 24 | 25 | public StringThread(String ip){ 26 | this.ip = ip; 27 | } 28 | 29 | /** 30 | * 构建锁 31 | * 32 | * @return 33 | */ 34 | private String buildLock(){ 35 | StringBuffer sb = new StringBuffer(PREFFIX).append(ip); 36 | // 以下两行代码会导致执行结果不一致 37 | // String lockString = sb.toString(); 38 | String lockString = sb.toString().intern(); 39 | System.out.println(Thread.currentThread().getName() + " 构建了锁:" + lockString); 40 | return lockString; 41 | } 42 | 43 | /* (non-Javadoc) 44 | * @see java.lang.Runnable#run() 45 | */ 46 | @Override 47 | public void run() { 48 | 49 | String lockString = buildLock(); 50 | synchronized(lockString){ 51 | System.out.println(Thread.currentThread().getName() + " 获取了锁"); 52 | try { 53 | Thread.sleep(3*1000); 54 | System.out.println(Thread.currentThread().getName() + " 执行业务完毕"); 55 | } catch (InterruptedException e) { 56 | e.printStackTrace(); 57 | } 58 | System.out.println(Thread.currentThread().getName() + " 释放了锁"); 59 | } 60 | } 61 | 62 | public static void main(String[] args) { 63 | 64 | final int THREAD_COUNT = 5; 65 | 66 | // Init 67 | Thread[] threads = new Thread[THREAD_COUNT]; 68 | for (int i = 0; i < threads.length; i++) { 69 | threads[i] = new Thread(new StringThread("192.168.1.1")); 70 | } 71 | 72 | // Fire 73 | for (int i = 0; i < threads.length; i++) { 74 | threads[i].start();; 75 | } 76 | 77 | // Ensure Main thread always running. 78 | for(;;); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/keyworld/sync/SynchronizedStudy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.keyworld.sync; 2 | 3 | /** 4 | * Synchronized 关键字学习 5 | * 6 | * @author taomk 2017年2月24日 下午9:19:20 7 | * 8 | */ 9 | public class SynchronizedStudy { 10 | 11 | public static void main(String[] args) { 12 | 13 | TxtThread t1 = new TxtThread(); 14 | new Thread(t1 , "T1-1").start(); 15 | new Thread(t1 , "T1-2").start(); 16 | new Thread(t1 , "T1-3").start(); 17 | 18 | // TxtThread t2 = new TxtThread(); 19 | // new Thread(t2 , "T2-1").start(); 20 | // new Thread(t2 , "T2-2").start(); 21 | // new Thread(t2 , "T2-3").start(); 22 | } 23 | 24 | 25 | } 26 | 27 | class TxtThread implements Runnable{ 28 | 29 | static Object o = new Object(); 30 | int num = 100; 31 | 32 | @Override 33 | public void run() { 34 | // synchronized(this){ 35 | while (num > 0) { 36 | // try { 37 | // Thread.sleep(100); 38 | // } catch (Exception e) { 39 | // e.printStackTrace(); 40 | // } 41 | reduce(); 42 | } 43 | // } 44 | } 45 | 46 | public synchronized void reduce(){ 47 | System.out.println(Thread.currentThread().getName() + "'num is " + num--); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/load/A.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.load; 2 | 3 | /** 4 | * @author taomk 2017年7月30日 下午5:10:50 5 | * 6 | */ 7 | public class A { 8 | 9 | { 10 | System.out.println("非静态代码块A"); 11 | } 12 | 13 | static { 14 | System.out.println("静态代码块A"); 15 | } 16 | 17 | A(){ 18 | System.out.println("无参构造函数A"); 19 | } 20 | 21 | A(int i){ 22 | System.out.println("有参构造函数A,i=" + i); 23 | } 24 | 25 | public static void main(String[] args) { 26 | @SuppressWarnings("unused") 27 | A ab = new B(); 28 | ab = new B(); 29 | // ab = new B(233); 30 | } 31 | } 32 | 33 | class B extends A{ 34 | 35 | { 36 | System.out.println("非静态代码块B"); 37 | } 38 | 39 | static { 40 | System.out.println("静态代码块B"); 41 | } 42 | 43 | static void bar() { 44 | System.out.println("静态方法bar()"); 45 | } 46 | 47 | B(){ 48 | // super(2); 49 | System.out.println("无参构造函数B"); 50 | } 51 | 52 | B(int j){ 53 | super(j); 54 | System.out.println("有参构造函数B,j=" + j); 55 | } 56 | 57 | void foo() { 58 | System.out.println("普通函数foo()"); 59 | } 60 | 61 | @SuppressWarnings("unused") 62 | public static void main(String[] args) { 63 | A ab = new B(); 64 | ab = new B(); 65 | ab = new B(233); 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/load/SSClass.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.load; 2 | 3 | public class SSClass { 4 | static{ 5 | System.out.println("SSClass init. "); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/load/StaticTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.load; 2 | 3 | /** 4 | *
 5 |  * 
 6 |  * http://blog.csdn.net/u013256816/article/details/50829596
 7 |  * 
 8 |  * http://blog.csdn.net/wangzi11322/article/details/44560243
 9 |  * 
10 |  * 
11 | * 12 | * @author taomk 2017年6月12日 上午11:08:49 13 | * 14 | */ 15 | public class StaticTest { 16 | 17 | public static void main(String[] args) { 18 | staticFunction(); 19 | } 20 | 21 | // 静态变量 22 | // static StaticTest st = new StaticTest(); 23 | 24 | // 普通变量 25 | StaticTest st = new StaticTest(); 26 | 27 | // 静态代码块 28 | static { 29 | System.out.println("1"); 30 | } 31 | 32 | // 代码块 33 | { 34 | System.out.println("2"); 35 | } 36 | 37 | // 构造函数 38 | StaticTest() { 39 | System.out.println("3"); 40 | System.out.println("a=" + a + ",b=" + b); 41 | } 42 | 43 | // 静态方法 44 | public static void staticFunction() { 45 | System.out.println("4"); 46 | } 47 | 48 | // 全局变量 49 | int a = 110; 50 | 51 | // 静态全局变量 52 | static int b = 120; 53 | } 54 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/load/SubClass.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.load; 2 | 3 | /** 4 | * @author taomk 2017年6月9日 下午2:02:02 5 | * 6 | */ 7 | public class SubClass extends SuperClass{ 8 | 9 | static{ 10 | System.out.println("SubClass init. "); 11 | } 12 | 13 | static int a; 14 | 15 | // public static String value = "SubClass.value"; 16 | 17 | public SubClass(){ 18 | System.out.println("SubClass constructor invoked. "); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/load/SuperClass.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.load; 2 | 3 | /** 4 | * @author taomk 2017年6月9日 下午1:59:57 5 | * 6 | */ 7 | public class SuperClass extends SSClass { 8 | 9 | static{ 10 | System.out.println("SuperClass init. "); 11 | } 12 | 13 | public static String value = "SSClass.value"; 14 | 15 | public SuperClass(){ 16 | System.out.println("SuperClass constructor invoked. "); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/load/Test.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.load; 2 | 3 | /** 4 | *
 5 |  * 
 6 |  * http://blog.csdn.net/u013256816/article/details/50829596
 7 |  * 
 8 |  * 对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过其子类来引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化。 
 9 |  * 
10 | * 11 | 12 | * @author taomk 2017年6月9日 下午2:03:46 13 | * 14 | */ 15 | public class Test { 16 | 17 | public static void main(String[] args) { 18 | System.out.println(SubClass.value); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/lock/count/Counter.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.lock.count; 2 | 3 | import java.util.concurrent.locks.Lock; 4 | import java.util.concurrent.locks.ReentrantLock; 5 | 6 | /** 7 | * 线程安全的计数器方法 8 | * 9 | * @author taomk 2017年6月14日 上午11:17:52 10 | * 11 | */ 12 | public class Counter { 13 | 14 | private Lock lock = new ReentrantLock(); 15 | private int count = 0; 16 | 17 | public int inc(){ 18 | lock.lock(); 19 | count++; 20 | lock.unlock(); 21 | return count; 22 | } 23 | 24 | public synchronized int get(){ 25 | return count; 26 | } 27 | } -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/lock/count/SharedVariableTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.lock.count; 2 | 3 | /** 4 | * 共享变量测试 5 | * 6 | * @author taomk 2017年8月14日 上午10:31:42 7 | * 8 | */ 9 | public class SharedVariableTest { 10 | 11 | private int count = 0; 12 | 13 | public static void main(String[] args) { 14 | 15 | SharedVariableTest svt1 = new SharedVariableTest(); 16 | // SharedVariableTest svt2 = new SharedVariableTest(); 17 | 18 | // 为不同对象创建的线程,线程之间不共享实例变量 19 | // T1 t1 = svt1.new T1(); 20 | // t1.start(); 21 | // 22 | // T2 t2 = svt2.new T2(); 23 | // new Thread(t2).start(); 24 | 25 | // 相同对象创建的线程,线程之间不共享实例变量 26 | T1 t1 = svt1.new T1(); 27 | t1.start(); 28 | 29 | T2 t2 = svt1.new T2(); 30 | new Thread(t2).start(); 31 | 32 | } 33 | 34 | class T1 extends Thread{ 35 | 36 | @Override 37 | public void run() { 38 | while(true) { 39 | try { 40 | Thread.sleep(1000); 41 | } catch (InterruptedException e) { 42 | e.printStackTrace(); 43 | } 44 | count++; 45 | System.out.println(Thread.currentThread().getName() + " count = " + count); 46 | } 47 | } 48 | } 49 | 50 | class T2 implements Runnable{ 51 | 52 | @Override 53 | public void run() { 54 | for(;;) { 55 | try { 56 | Thread.sleep(1000); 57 | } catch (InterruptedException e) { 58 | e.printStackTrace(); 59 | } 60 | System.out.println(Thread.currentThread().getName() + " count = " + count); 61 | } 62 | } 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/lock/count/Test.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.lock.count; 2 | 3 | /** 4 | * 测试类 5 | * 6 | * @author taomk 2017年6月14日 上午11:22:26 7 | * 8 | */ 9 | public class Test { 10 | 11 | public static void main(String[] args) { 12 | 13 | Counter c = new Counter(); 14 | 15 | new Thread("T-1"){ 16 | 17 | @SuppressWarnings("unused") 18 | @Override 19 | public void run() { 20 | 21 | Counter c1 = new Counter(); 22 | for (int i = 0; i < 100; i++) { 23 | // System.out.println(Thread.currentThread().getName() + " : " + c1.inc()); 24 | System.out.println(Thread.currentThread().getName() + " increase ... " + c.inc()); 25 | } 26 | } 27 | }.start();; 28 | 29 | new Thread("T-2"){ 30 | 31 | @SuppressWarnings("unused") 32 | Counter c2 = new Counter(); 33 | 34 | @Override 35 | public void run() { 36 | for (int i = 0; i < 200; i++) { 37 | 38 | // System.out.println(Thread.currentThread().getName() + " : " + c2.inc()); 39 | System.out.println(Thread.currentThread().getName() + " get ... " + c.get()); 40 | 41 | } 42 | } 43 | }.start();; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/lock/wait/DeadLock.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.lock.wait; 2 | 3 | /** 4 | *
 5 |  * {@link https://segmentfault.com/q/1010000009461368}
 6 |  * 回头再看,好像就是自己实现了一个blocking queue呢
 7 |  * 
8 | * @author taomk 2017年5月18日 上午10:48:08 9 | * 10 | */ 11 | public class DeadLock { 12 | 13 | // 锁对象,之所以这么创建是为了尽量减少内存消耗 14 | private byte[] lock = new byte[0]; 15 | 16 | // 生产开关flag 17 | private volatile boolean isProduct = false; 18 | 19 | // 计数 20 | private int count = 0; 21 | 22 | /** 23 | * 生产动作 24 | */ 25 | public void produce() { 26 | synchronized (lock) { 27 | if (isProduct) { 28 | try { 29 | System.out.println("produce loop..."); 30 | lock.wait(); 31 | } catch (InterruptedException e) { 32 | e.printStackTrace(); 33 | } 34 | } else { 35 | count++; 36 | System.out.println("P ---> " + count); 37 | lock.notify(); 38 | isProduct = true; 39 | } 40 | } 41 | } 42 | 43 | /** 44 | * 消费动作 45 | */ 46 | public void consume() { 47 | synchronized (lock) { 48 | if (isProduct) { 49 | System.out.println("C ---> " + count); 50 | lock.notify(); 51 | isProduct = false; 52 | } else { 53 | try { 54 | System.out.println("consume loop..."); 55 | lock.wait(); 56 | } catch (InterruptedException e) { 57 | e.printStackTrace(); 58 | } 59 | } 60 | } 61 | } 62 | 63 | public static void main(String[] args) { 64 | 65 | DeadLock d = new DeadLock(); 66 | new Thread(() -> { 67 | for (int i = 0; i < 10; i++) { 68 | d.consume(); 69 | } 70 | }).start(); 71 | 72 | new Thread(){ 73 | @Override 74 | public void run() { 75 | try { 76 | System.out.println("Sleeping"); 77 | sleep(1*1000); 78 | } catch (Exception e) { 79 | e.printStackTrace(); 80 | } 81 | 82 | for (int i = 0; i < 10; i++) { 83 | d.produce(); 84 | } 85 | } 86 | }.start(); 87 | 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/lock/wait/Restaurant.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.lock.wait; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | /** 8 | * 生产者-消费者问题
9 | * 10 | * https://zhuanlan.zhihu.com/p/25474331 11 | * 12 | * @author taomk 2017年8月16日 下午8:50:34 13 | * 14 | */ 15 | public class Restaurant { 16 | 17 | Meal meal; 18 | ExecutorService exec = Executors.newCachedThreadPool(); 19 | WaitPerson waitPerson = new WaitPerson(this); 20 | Chef chef = new Chef(this); 21 | 22 | public Restaurant() { 23 | exec.execute(chef); 24 | exec.execute(waitPerson); 25 | } 26 | 27 | public static void main(String[] args) { 28 | new Restaurant(); 29 | } 30 | } 31 | 32 | /** 33 | * 物料 34 | * 35 | * @author taomk 2017年8月16日 下午9:01:41 36 | * 37 | */ 38 | class Meal { 39 | 40 | /** 41 | * 编号 42 | */ 43 | private final int orderNum; 44 | 45 | public Meal(int orderNum) { 46 | this.orderNum = orderNum; 47 | } 48 | 49 | public String toString() { 50 | return "Meal " + orderNum; 51 | } 52 | } 53 | 54 | /** 55 | * 消费者 56 | * 57 | * @author taomk 2017年8月16日 下午9:03:55 58 | * 59 | */ 60 | class WaitPerson implements Runnable { 61 | 62 | private Restaurant restaurant; 63 | 64 | public WaitPerson(Restaurant r) { 65 | this.restaurant = r; 66 | } 67 | 68 | @Override 69 | public void run() { 70 | try { 71 | while (!Thread.interrupted()) { 72 | synchronized (this) { 73 | while (restaurant.meal == null) 74 | wait();// ..for the chef to produce a meal 75 | } 76 | System.out.println("WaitPerson got " + restaurant.meal); 77 | synchronized (restaurant.chef) { 78 | restaurant.meal = null; 79 | restaurant.chef.notifyAll();// ready for another 80 | } 81 | } 82 | TimeUnit.MICROSECONDS.sleep(100); 83 | } catch (InterruptedException e) { 84 | System.out.println("WaitPerson interrupted"); 85 | } 86 | } 87 | } 88 | 89 | /** 90 | * 生产者 91 | * 92 | * @author taomk 2017年8月16日 下午9:05:05 93 | * 94 | */ 95 | class Chef implements Runnable { 96 | 97 | private Restaurant restaurant; 98 | private int count = 0; 99 | 100 | public Chef(Restaurant r) { 101 | this.restaurant = r; 102 | } 103 | 104 | @Override 105 | public void run() { 106 | try { 107 | while (!Thread.interrupted()) { 108 | synchronized (this) { 109 | while (restaurant.meal != null) 110 | wait();// ...for the meal to be taken 111 | } 112 | if (++count == 10) {// produce food , until count > 9 113 | System.out.println("Out of food,closing"); 114 | restaurant.exec.shutdownNow(); 115 | } 116 | System.out.println("Order up!"); 117 | synchronized (restaurant.waitPerson) { 118 | restaurant.meal = new Meal(count); 119 | restaurant.waitPerson.notifyAll(); 120 | } 121 | 122 | } 123 | } catch (InterruptedException e) { 124 | } 125 | } 126 | } -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/lock/wait/WaitTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.lock.wait; 2 | 3 | /** 4 | * https://zhuanlan.zhihu.com/p/25474331 5 | * 6 | * @author taomk 2017年8月11日 下午4:17:52 7 | * 8 | */ 9 | public class WaitTest { 10 | 11 | public static String a = "";// 作为监视器对象 12 | 13 | public static void main(String[] args) throws InterruptedException { 14 | 15 | TestTask task = new WaitTest().new TestTask(); 16 | 17 | Thread t = new Thread(task); 18 | 19 | t.start(); 20 | 21 | // 让当前线程(主线程)睡眠指定毫秒数,一直持有当前线程的线程监视器 22 | Thread.sleep(12*1000); 23 | 24 | for (int i = 5; i > 0; i--) { 25 | System.out.println("快唤醒挂起的线程************"); 26 | Thread.sleep(1000); 27 | } 28 | 29 | System.out.println("收到,马上!唤醒挂起的线程************"); 30 | 31 | synchronized (a) { 32 | a.notifyAll(); 33 | } 34 | } 35 | 36 | class TestTask implements Runnable { 37 | 38 | @Override 39 | public void run() { 40 | synchronized (a) { 41 | try { 42 | 43 | for (int i = 1; i < 11; i++) { 44 | Thread.sleep(1000); 45 | System.out.println("我在运行 ...... * " + i); 46 | } 47 | 48 | a.wait(); 49 | 50 | for (int i = 10; i > 0; i--) { 51 | System.out.println("谢谢唤醒 ...... ,又开始运行了*******"); 52 | } 53 | } catch (InterruptedException e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/map/HashMapThread.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.map; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.concurrent.atomic.AtomicInteger; 6 | 7 | /** 8 | * HashMap在高并发下可能导致的并发异常 9 | * 10 | * @author taomk 2017年8月7日 下午2:33:55 11 | * 12 | */ 13 | public class HashMapThread extends Thread{ 14 | 15 | private static AtomicInteger ai = new AtomicInteger(); 16 | private static Map m = new HashMap(1); 17 | 18 | @Override 19 | public void run() { 20 | while(ai.get()<1000*1000){ 21 | m.put(ai.get(), ai.get()); 22 | ai.incrementAndGet(); 23 | } 24 | } 25 | 26 | public static void main(String[] args) { 27 | 28 | HashMapThread hmt0 = new HashMapThread(); 29 | HashMapThread hmt1 = new HashMapThread(); 30 | HashMapThread hmt2 = new HashMapThread(); 31 | HashMapThread hmt3 = new HashMapThread(); 32 | HashMapThread hmt4 = new HashMapThread(); 33 | 34 | hmt0.start(); 35 | hmt1.start(); 36 | hmt2.start(); 37 | hmt3.start(); 38 | hmt4.start(); 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/map/LinkedHashMapStudy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.map; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.Map.Entry; 5 | 6 | /** 7 | *
 8 |  * 	LinkedHashMap 学习
 9 |  * 
10 | * 11 | * @see LinkedHashMap 12 | * @author taomk 2017年6月16日 上午10:17:09 13 | * 14 | */ 15 | public class LinkedHashMapStudy { 16 | 17 | public static void main(String[] args) { 18 | 19 | // 默认按照插入顺序排序(accessOrder默认为faslse) 20 | LinkedHashMap lmap = new LinkedHashMap(); 21 | lmap.put("语文", 1); 22 | lmap.put("数学", 2); 23 | lmap.put("英语", 3); 24 | lmap.put("历史", 4); 25 | lmap.put("政治", 5); 26 | lmap.put("地理", 6); 27 | lmap.put("生物", 7); 28 | lmap.put("化学", 8); 29 | lmap.put("物理", 9); 30 | 31 | System.out.println("成绩列表:"); 32 | // 可以看出是按照元素的插入顺序来迭代输出的 33 | for (Entry entry : lmap.entrySet()) { 34 | System.out.println("\t" + entry.getKey() + ": " + entry.getValue()); 35 | } 36 | 37 | System.out.println("_________________________LRU_________________________"); 38 | 39 | 40 | LinkedHashMap linkedHashMap = new LinkedHashMap(16, 0.75F, true); 41 | linkedHashMap.put("语文", 1); 42 | linkedHashMap.put("数学", 2); 43 | linkedHashMap.put("英语", 3); 44 | linkedHashMap.put("历史", 4); 45 | linkedHashMap.put("政治", 5); 46 | linkedHashMap.put("地理", 6); 47 | linkedHashMap.put("生物", 7); 48 | linkedHashMap.put("化学", 8); 49 | linkedHashMap.put("物理", 9); 50 | System.out.println("副科成绩:"); 51 | System.out.println("\t历史:"+linkedHashMap.get("历史")); 52 | System.out.println("\t政治:"+linkedHashMap.get("政治")); 53 | System.out.println("\t地理:"+linkedHashMap.get("地理")); 54 | System.out.println("\t生物:"+linkedHashMap.get("生物")); 55 | System.out.println("\t化学:"+linkedHashMap.get("化学")); 56 | System.out.println("\t物理:"+linkedHashMap.get("物理")); 57 | 58 | System.out.println("主科成绩:"); 59 | System.out.println("\t语文:"+linkedHashMap.get("语文")); 60 | System.out.println("\t数学:"+linkedHashMap.get("数学")); 61 | System.out.println("\t英语:"+linkedHashMap.get("英语")); 62 | 63 | System.out.println("成绩列表:"); 64 | // 可以看出是按照元素的插入顺序来迭代输出的 65 | for (Entry entry : linkedHashMap.entrySet()) { 66 | System.out.println("\t" + entry.getKey() + ": " + entry.getValue()); 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/method_interface/BlockingQueueStudy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.method_interface; 2 | 3 | import java.util.concurrent.ArrayBlockingQueue; 4 | import java.util.concurrent.BlockingQueue; 5 | 6 | /** 7 | * BlockingQueue 研究 8 | * @author taomk 2017年3月1日 下午10:36:39 9 | * 10 | */ 11 | public class BlockingQueueStudy { 12 | 13 | public static void main(String[] args) throws InterruptedException { 14 | 15 | BlockingQueue queue = new ArrayBlockingQueue(1024); 16 | 17 | new Thread(new Producer(queue)).start(); 18 | new Thread(new Consumer(queue)).start(); 19 | 20 | Thread.sleep(3*1000); 21 | } 22 | 23 | } 24 | 25 | 26 | /** 27 | * 生产者 28 | * 29 | * @author taomk 2017年3月1日 下午10:49:13 30 | * 31 | */ 32 | class Producer implements Runnable{ 33 | 34 | private BlockingQueue queue; 35 | 36 | Producer(BlockingQueue queue){ 37 | this.queue = queue; 38 | } 39 | 40 | @Override 41 | public void run() { 42 | try { 43 | queue.put("A"); 44 | Thread.sleep(1000); 45 | queue.put("B"); 46 | Thread.sleep(1000); 47 | queue.put("C"); 48 | } catch (InterruptedException e) { 49 | e.printStackTrace(); 50 | } 51 | } 52 | } 53 | 54 | /** 55 | * 消费者 56 | * 57 | * @author taomk 2017年3月1日 下午10:48:57 58 | * 59 | */ 60 | class Consumer implements Runnable{ 61 | 62 | private BlockingQueue queue; 63 | 64 | Consumer(BlockingQueue queue){ 65 | this.queue = queue; 66 | } 67 | 68 | @Override 69 | public void run() { 70 | try { 71 | System.out.println(queue.take()); 72 | System.out.println(queue.take()); 73 | System.out.println(queue.take()); 74 | } catch (InterruptedException e) { 75 | e.printStackTrace(); 76 | } 77 | } 78 | 79 | } -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/method_interface/CallableAndFutureStudy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.method_interface; 2 | 3 | import java.util.Random; 4 | import java.util.concurrent.Callable; 5 | import java.util.concurrent.ExecutionException; 6 | import java.util.concurrent.FutureTask; 7 | 8 | /** 9 | * Callable FutureTask Study 10 | * @author taomk 2017年3月10日 下午9:20:12 11 | * 12 | */ 13 | public class CallableAndFutureStudy { 14 | 15 | public static void main(String[] args){ 16 | 17 | Callable call = new Callable(){ 18 | @Override 19 | public Integer call() throws Exception{ 20 | return new Random().nextInt(100); 21 | } 22 | }; 23 | 24 | FutureTask task =new FutureTask(call); 25 | new Thread(task).start(); 26 | 27 | try { 28 | System.out.println("Other things ..."); 29 | System.out.println(task.get()); 30 | } catch (InterruptedException | ExecutionException e) { 31 | e.printStackTrace(); 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/method_interface/ClassLoaderStudy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.method_interface; 2 | 3 | /** 4 | * @author taomk 2017年3月5日 下午5:47:46 5 | * 6 | */ 7 | public class ClassLoaderStudy { 8 | 9 | public static void main(String[] args) { 10 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); 11 | System.out.println("Current Loader : " + loader); 12 | System.out.println("Parent Loader : " + loader.getParent()); 13 | System.out.println("Grandparent Loader : " + loader.getParent().getParent()); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/method_interface/DelayQueueStudy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.method_interface; 2 | 3 | import java.util.concurrent.BlockingQueue; 4 | import java.util.concurrent.DelayQueue; 5 | import java.util.concurrent.Delayed; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | /** 9 | * 10 | * 11 | * @author taomk 2017年3月2日 下午4:44:08 12 | * 13 | */ 14 | public class DelayQueueStudy { 15 | 16 | /** 17 | * @param args 18 | * @throws InterruptedException 19 | */ 20 | public static void main(String[] args) throws InterruptedException { 21 | BlockingQueue queue = new DelayQueue(); 22 | 23 | Delayed element1 = new DelayedElement(); 24 | queue.put(element1); 25 | 26 | DelayedElement element2 = (DelayedElement)queue.take(); 27 | System.out.println(element2.showState()); 28 | } 29 | 30 | } 31 | 32 | class DelayedElement implements Delayed{ 33 | 34 | public String showState(){ 35 | return "OK"; 36 | } 37 | 38 | @Override 39 | public int compareTo(Delayed o) { 40 | return 0; 41 | } 42 | 43 | @Override 44 | public long getDelay(TimeUnit unit) { 45 | return unit.toSeconds(3*1000); 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/method_interface/MapStudy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.method_interface; 2 | 3 | import java.util.Iterator; 4 | import java.util.LinkedHashMap; 5 | import java.util.Map; 6 | import java.util.Map.Entry; 7 | 8 | /** 9 | * Map Study 10 | * 11 | * @author taomk 2017年3月14日 下午9:55:31 12 | * 13 | */ 14 | public class MapStudy { 15 | 16 | public static void main(String[] args) { 17 | 18 | System.out.println("accessOrder为false时(默认为false),基于插入顺序来获取元素"); 19 | LinkedHashMap lhm = new LinkedHashMap(12, 0.75F, false); 20 | fillData(lhm); 21 | lhm.get("24"); 22 | lhm.get("23"); 23 | lhm.get("21"); 24 | lhm.get("7"); 25 | lhm.get("6"); 26 | lhm.get("3"); 27 | lhm.get("2"); 28 | showData(lhm); 29 | 30 | System.out.println("accessOrder为true时,get一个元素后,这个元素被加到最后(使用了LRU 最近最少被使用的调度算法)"); 31 | 32 | lhm = new LinkedHashMap(12, 0.75F, true); 33 | fillData(lhm); 34 | lhm.get("24"); 35 | lhm.get("23"); 36 | lhm.get("21"); 37 | lhm.get("7"); 38 | lhm.get("6"); 39 | lhm.get("3"); 40 | showData(lhm); 41 | } 42 | 43 | private static void fillData(Map lhm){ 44 | lhm.put("0", "McGrady"); 45 | lhm.put("2", "Irving"); 46 | lhm.put("3", "Ai"); 47 | lhm.put("6", "James"); 48 | lhm.put("7", "Anthony"); 49 | lhm.put("21", "TD"); 50 | lhm.put("23", "Jordan"); 51 | lhm.put("24", "Kobe"); 52 | } 53 | 54 | private static void showData(Map lhm){ 55 | for (Iterator> iterator = lhm.entrySet().iterator(); iterator.hasNext();) { 56 | Entry entry = iterator.next(); 57 | System.out.println(entry.getKey() + " : " + entry.getValue()); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/method_interface/NotifyStusy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.method_interface; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * notify()、wait()研究 7 | * 8 | * @author taomk 2017年2月26日 下午10:03:22 9 | * 10 | */ 11 | public class NotifyStusy { 12 | 13 | 14 | public static void main(String[] args) { 15 | 16 | final Object lock = new Object(); 17 | 18 | new Thread(){ 19 | @Override 20 | public void run(){ 21 | try { 22 | synchronized (lock) { 23 | System.out.println(Thread.currentThread() + " get the lock @ " + new Date()); 24 | Thread.sleep(8 * 1000); 25 | System.out.println(Thread.currentThread() + " end @ " + new Date()); 26 | } 27 | } catch (Exception e) { 28 | e.printStackTrace(); 29 | } 30 | } 31 | }.start(); 32 | 33 | try { 34 | 35 | System.out.println(Thread.currentThread() + " start run @ " + new Date()); 36 | Thread.sleep(3 * 1000); 37 | System.out.println(Thread.currentThread() + " end run @ " + new Date()); 38 | 39 | synchronized(lock){ 40 | System.out.println(Thread.currentThread() + ", get the lock @ " + new Date()); 41 | lock.notify(); 42 | System.out.println("lock.notify();"); 43 | Thread.sleep(5 * 1000); 44 | System.out.println(Thread.currentThread() + " end @ " + new Date()); 45 | } 46 | 47 | } catch (Exception e) { 48 | e.printStackTrace(); 49 | } 50 | 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/method_interface/ProxyStudy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.method_interface; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Method; 5 | import java.lang.reflect.Proxy; 6 | 7 | /** 8 | * Proxy Study 9 | * 10 | * @author taomk 2017年3月5日 下午9:33:33 11 | * 12 | */ 13 | public class ProxyStudy { 14 | 15 | public static void main(String[] args) { 16 | 17 | ForumService serviceImpl = new ForumServiceImpl(); 18 | PerformanceHandler handler = new PerformanceHandler(serviceImpl); 19 | 20 | // Proxy.newProxyInstance 21 | // 方法的第一个入参为类加载器; 22 | // 第二个入参为创建代理实例所需要实现的一组接口;因此,使用JDK创建代理有一个限制,即它只能为接口创建代理实例 23 | // 第三个参数是整合了业务逻辑和横切逻辑的编织器对象 24 | ForumService proxy = (ForumService) Proxy.newProxyInstance(serviceImpl.getClass().getClassLoader(), 25 | serviceImpl.getClass().getInterfaces(), handler); 26 | 27 | proxy.removeForum("ae78bcg"); 28 | proxy.removeTopic("Ng990xs"); 29 | } 30 | 31 | } 32 | 33 | /** 34 | * 业务类接口定义 35 | * 36 | * @author taomk 2017年3月5日 下午9:35:29 37 | * 38 | */ 39 | interface ForumService { 40 | void removeTopic(String topicId); 41 | 42 | void removeForum(String forumId); 43 | } 44 | 45 | /** 46 | * 业务类接口实现 47 | * 48 | * @author taomk 2017年3月5日 下午9:36:15 49 | * 50 | */ 51 | class ForumServiceImpl implements ForumService { 52 | 53 | @Override 54 | public void removeTopic(String topicId) { 55 | 56 | System.out.println("业务方法,模拟删除Topic记录:" + topicId); 57 | 58 | try { 59 | Thread.sleep(200); 60 | } catch (InterruptedException e) { 61 | e.printStackTrace(); 62 | } 63 | 64 | } 65 | 66 | @Override 67 | public void removeForum(String forumId) { 68 | 69 | System.out.println("业务方法,模拟删除Forum记录:" + forumId); 70 | 71 | try { 72 | Thread.sleep(200); 73 | } catch (InterruptedException e) { 74 | e.printStackTrace(); 75 | } 76 | 77 | } 78 | 79 | } 80 | 81 | /** 82 | * 通过InvocationHandler将业务逻辑和性能监控逻辑交织 83 | * 84 | * @author taomk 2017年3月5日 下午9:48:20 85 | * 86 | */ 87 | class PerformanceHandler implements InvocationHandler { 88 | 89 | private Object target; 90 | 91 | public PerformanceHandler(Object target) { 92 | this.target = target; 93 | } 94 | 95 | @Override 96 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 97 | 98 | MethodPerformance performance = new MethodPerformance(target.getClass().getName() + "." + method.getName()); 99 | performance.start(); 100 | 101 | Object result = method.invoke(target, args); 102 | 103 | performance.printPerformance(); 104 | 105 | return result; 106 | } 107 | 108 | } 109 | 110 | /** 111 | * 性能计算工具类 112 | * 113 | * @author taomk 2017年3月5日 下午9:44:51 114 | * 115 | */ 116 | class MethodPerformance { 117 | 118 | private long startTime; 119 | private long endTime; 120 | private String serviceName; 121 | 122 | MethodPerformance(String serviceName) { 123 | this.serviceName = serviceName; 124 | } 125 | 126 | public void start() { 127 | this.startTime = System.currentTimeMillis(); 128 | } 129 | 130 | public void printPerformance() { 131 | this.endTime = System.currentTimeMillis(); 132 | long elapse = endTime - startTime; 133 | System.out.println("[" + serviceName + "],花费时间(ms):" + elapse); 134 | } 135 | } -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/method_interface/ReflectStudy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.method_interface; 2 | 3 | import java.lang.reflect.Constructor; 4 | import java.lang.reflect.InvocationTargetException; 5 | import java.lang.reflect.Method; 6 | 7 | /** 8 | * reflect 研究 9 | * @author taomk 2017年3月5日 下午6:15:29 10 | * 11 | */ 12 | public class ReflectStudy { 13 | 14 | public static void main(String[] args) { 15 | try { 16 | Class carClass = Class.forName("com.taomk.understandingJVM.method_interface.PrivateCar"); 17 | // ClassLoader loader = Thread.currentThread().getContextClassLoader(); 18 | // Class carClass = loader.loadClass("com.taomk.understandingJVM.method_interface.PrivateCar"); 19 | 20 | Constructor constructor = carClass.getDeclaredConstructor(new Class[]{String.class , String.class}); 21 | PrivateCar aRealCar = (PrivateCar) constructor.newInstance("white" , "lily"); 22 | 23 | // PrivateCar aRealCar = (PrivateCar) carClass.newInstance(); 24 | 25 | // Field[] fields = carClass.getDeclaredFields(); 26 | // for (Field field : fields) { 27 | // if(!field.isAccessible()){ 28 | // field.setAccessible(true); 29 | // } 30 | // if(field.getName().equals("color")){ 31 | // field.set(aRealCar, "black"); 32 | // }else if(field.getName().equals("owner")){ 33 | // field.set(aRealCar, "taomk"); 34 | // } 35 | // } 36 | 37 | // Field color = carClass.getDeclaredField("color"); 38 | // color.setAccessible(true); 39 | // color.set(aRealCar, "black"); 40 | 41 | Method drive = carClass.getDeclaredMethod("drive", (Class[])null); 42 | drive.setAccessible(true); 43 | drive.invoke(aRealCar, (Object[])null); 44 | 45 | } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | SecurityException | NoSuchMethodException | IllegalArgumentException | InvocationTargetException e) { 46 | e.printStackTrace(); 47 | } 48 | } 49 | 50 | } 51 | 52 | 53 | class PrivateCar{ 54 | 55 | /** 56 | * 属性:车的主人,public 方法,无任何限制 57 | */ 58 | public String owner; 59 | /** 60 | * 属性:车的颜色,private 方法,只允许在本类内部使用 61 | */ 62 | private String color; 63 | 64 | /** 65 | * 构造函数 66 | * 67 | * @param ownerName 68 | * @param color 69 | */ 70 | PrivateCar(String ownerName , String color){ 71 | this.owner = ownerName; 72 | this.color = color; 73 | } 74 | 75 | /** 76 | * 方法:开车,protected 方法,允许子类和同包的类使用 77 | */ 78 | protected void drive(){ 79 | System.out.println(owner + " driving a " + color + " car ..."); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/method_interface/SerializeStudy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.method_interface; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.FileNotFoundException; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.io.ObjectInputStream; 8 | import java.io.ObjectOutputStream; 9 | import java.io.Serializable; 10 | 11 | /** 12 | * Serializable 13 | * 14 | * @author taomk 2017年2月25日 下午9:33:08 15 | * 16 | */ 17 | public class SerializeStudy extends SerializeStudyParent implements Serializable{ 18 | 19 | SerializeStudy(String parentCommonStr) { 20 | super(parentCommonStr); 21 | } 22 | 23 | private static final long serialVersionUID = 1L; 24 | 25 | /** 26 | * 静态变量 27 | */ 28 | public static int staticVal = 5; 29 | 30 | /** 31 | * 普通属性 32 | */ 33 | private String commonStr = "abc"; 34 | 35 | /** 36 | * 被transient关键字修饰的属性 37 | */ 38 | private transient String transientStr = "123"; 39 | 40 | public static void main(String[] args) { 41 | 42 | try { 43 | 44 | SerializeStudy a = new SerializeStudy("world"); 45 | // 序列化对象到本地文件,此时静态属性staticVal的值是5 46 | ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("example.object")); 47 | out.writeObject(a); 48 | out.flush(); 49 | out.close(); 50 | 51 | // 将静态属性的值改为10 52 | SerializeStudy.staticVal = 10; 53 | a.commonStr = "xyz"; 54 | 55 | // 从文件中读取序列化后的对象 56 | ObjectInputStream in = new ObjectInputStream(new FileInputStream("example.object")); 57 | SerializeStudy b = (SerializeStudy) in.readObject(); 58 | in.close(); 59 | 60 | System.out.println(SerializeStudy.staticVal);//序列化保存的是对象的状态,静态变量属于类的状态,因此 序列化并不保存静态变量。 61 | System.out.println(b.commonStr); 62 | System.out.println(b.transientStr); 63 | System.out.println(b.parentCommonStr); 64 | 65 | } catch (FileNotFoundException e) { 66 | e.printStackTrace(); 67 | } catch (IOException e) { 68 | e.printStackTrace(); 69 | } catch (ClassNotFoundException e) { 70 | e.printStackTrace(); 71 | } 72 | 73 | 74 | } 75 | 76 | } 77 | 78 | 79 | class SerializeStudyParent{ 80 | public String parentCommonStr = "hello"; 81 | SerializeStudyParent(String parentCommonStr){ 82 | this.parentCommonStr = parentCommonStr; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/nio/FileChannelTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.nio; 2 | 3 | import java.io.IOException; 4 | import java.io.RandomAccessFile; 5 | import java.nio.ByteBuffer; 6 | import java.nio.CharBuffer; 7 | import java.nio.MappedByteBuffer; 8 | import java.nio.channels.FileChannel; 9 | import java.nio.channels.FileChannel.MapMode; 10 | import java.nio.charset.Charset; 11 | import java.nio.charset.CharsetDecoder; 12 | 13 | /** 14 | * http://www.iteye.com/magazines/132-Java-NIO 15 | * 16 | * @author taomk 2017年8月8日 下午6:34:10 17 | * 18 | */ 19 | public class FileChannelTest { 20 | 21 | public static void main(String[] args) throws IOException { 22 | 23 | // String filePath = "/Users/Dev/github/understandingJVM/README.md"; 24 | // readFile(filePath); 25 | // 26 | // String toFile = "/Users/Dev/github/understandingJVM/nio-data.txt"; 27 | // String content = "New String to write to file...\n当前毫秒数:" + System.currentTimeMillis(); 28 | // writeToFile(content, toFile); 29 | 30 | String bigFile = "/Users/Tao/Downloads/Spring实战.pdf"; 31 | readBigFile1(bigFile); 32 | readBigFile2(bigFile); 33 | 34 | } 35 | 36 | public static void readFile(String filePath) throws IOException { 37 | RandomAccessFile raf = null; 38 | try { 39 | // Java.nio.charset.Charset处理了字符转换问题。 40 | // 它通过构造CharsetEncoder和CharsetDecoder将字符序列转换成字节和逆转换。 41 | Charset charset = Charset.forName("UTF-8"); 42 | CharsetDecoder decoder = charset.newDecoder(); 43 | 44 | raf = new RandomAccessFile(filePath, "rw"); 45 | FileChannel channel = raf.getChannel(); 46 | 47 | ByteBuffer buffer = ByteBuffer.allocate(1024); 48 | CharBuffer charBuffer = CharBuffer.allocate(1024); 49 | 50 | // 将数据读取到buffer 51 | int bytesRead = channel.read(buffer); 52 | System.out.println("Size : " + channel.size()); 53 | while (bytesRead != -1) { 54 | System.out.println("Read : " + bytesRead); 55 | // 切换buffer模式,从写模式转为读模式 56 | buffer.flip(); 57 | 58 | decoder.decode(buffer, charBuffer, false); 59 | 60 | charBuffer.flip(); 61 | 62 | System.out.println("Content : "); 63 | while (charBuffer.hasRemaining()) { 64 | // 读取数据 65 | System.out.print(charBuffer.get()); 66 | } 67 | // clear或者compact, 68 | // clear会清空整个缓存, 69 | // 而compact只会清除已读的数据、未读的数据会移动到缓冲区的起始处 70 | buffer.clear(); 71 | // 将数据读取到buffer 72 | bytesRead = channel.read(buffer); 73 | } 74 | 75 | } catch (IOException e) { 76 | e.printStackTrace(); 77 | } finally { 78 | if (raf != null) { 79 | raf.close(); 80 | } 81 | } 82 | } 83 | 84 | public static void writeToFile(String content, String file) throws IOException { 85 | RandomAccessFile aFile = new RandomAccessFile(file, "rw"); 86 | FileChannel channel = aFile.getChannel(); 87 | 88 | ByteBuffer buffer = ByteBuffer.allocate(64); 89 | buffer.clear(); 90 | buffer.put(content.getBytes()); 91 | 92 | buffer.flip(); 93 | 94 | while (buffer.hasRemaining()) { 95 | channel.write(buffer); 96 | } 97 | aFile.close(); 98 | } 99 | 100 | /** 101 | * 使用ByteBuffer来读取一个较大文件的效率 102 | * 103 | * @param filePath 104 | * @throws IOException 105 | */ 106 | public static void readBigFile1(String filePath) throws IOException { 107 | RandomAccessFile rfa = null; 108 | FileChannel fc = null; 109 | try { 110 | 111 | System.out.println("=============readBigFile1============="); 112 | 113 | rfa = new RandomAccessFile(filePath, "r"); 114 | fc = rfa.getChannel(); 115 | 116 | System.out.println("Size : " + rfa.length()); 117 | 118 | long startTime = System.currentTimeMillis(); 119 | 120 | ByteBuffer buffer = ByteBuffer.allocate((int) fc.size()); 121 | buffer.clear(); 122 | fc.read(buffer); 123 | System.out.println(buffer.getChar((int) (fc.size()/2))); 124 | 125 | long endTime = System.currentTimeMillis(); 126 | System.out.println("readBigFile1(ms) : " + (endTime-startTime)); 127 | } catch (Exception e) { 128 | System.err.println(e); 129 | }finally { 130 | if(rfa!=null) { 131 | rfa.close(); 132 | } 133 | if(fc!=null) { 134 | fc.close(); 135 | } 136 | } 137 | } 138 | 139 | /** 140 | * 使用MappedByteBuffer来读取一个较大文件 141 | * 142 | * @param filePath 143 | * @throws IOException 144 | */ 145 | public static void readBigFile2(String filePath) throws IOException { 146 | RandomAccessFile rfa = null; 147 | FileChannel fc = null; 148 | try { 149 | 150 | System.out.println("=============readBigFile2============="); 151 | 152 | rfa = new RandomAccessFile(filePath, "r"); 153 | fc = rfa.getChannel(); 154 | 155 | System.out.println("Size : " + rfa.length()); 156 | 157 | long startTime = System.currentTimeMillis(); 158 | 159 | MappedByteBuffer mappedBuffer = fc.map(MapMode.READ_ONLY, 0, fc.size()); 160 | 161 | System.out.println(mappedBuffer.getChar((int) (rfa.length()/2))); 162 | 163 | long endTime = System.currentTimeMillis(); 164 | System.out.println("readBigFile1(ms) : " + (endTime-startTime)); 165 | } catch (Exception e) { 166 | System.err.println(e); 167 | }finally { 168 | if(rfa!=null) { 169 | rfa.close(); 170 | } 171 | if(fc!=null) { 172 | fc.close(); 173 | } 174 | } 175 | } 176 | 177 | } 178 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/nio/SocketChannelTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.nio; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.net.InetSocketAddress; 6 | import java.net.ServerSocket; 7 | import java.net.Socket; 8 | import java.net.SocketAddress; 9 | import java.nio.ByteBuffer; 10 | import java.nio.channels.SelectionKey; 11 | import java.nio.channels.Selector; 12 | import java.nio.channels.ServerSocketChannel; 13 | import java.nio.channels.SocketChannel; 14 | import java.util.Iterator; 15 | import java.util.concurrent.TimeUnit; 16 | 17 | /** 18 | * http://www.importnew.com/19816.html 19 | * 20 | * @author taomk 2017年8月8日 下午10:29:54 21 | * 22 | */ 23 | public class SocketChannelTest { 24 | 25 | public static void main(String[] args) throws InterruptedException { 26 | 27 | // Thread serverThread = new Thread(() -> server()); 28 | Thread serverThread = new Thread(() -> ServerConnect.main(args)); 29 | serverThread.start(); 30 | 31 | Thread clientThread1 = new Thread(() -> client()); 32 | // Thread clientThread2 = new Thread(() -> client()); 33 | clientThread1.start(); 34 | // clientThread2.start(); 35 | 36 | Thread.currentThread().join(); 37 | } 38 | 39 | /** 40 | * NIO方式实现的客户端 41 | */ 42 | public static void client() { 43 | ByteBuffer buffer = ByteBuffer.allocate(1024); 44 | SocketChannel socketChannel = null; 45 | try { 46 | 47 | socketChannel = SocketChannel.open();// 打开SocketChannel 48 | socketChannel.configureBlocking(false);// 配置非阻塞 49 | socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080));// 建立连接 50 | 51 | if (socketChannel.finishConnect()) {// 如果client与Server创建连接完毕 52 | int i = 0; 53 | while (true) {// 一直保持活跃状态 54 | TimeUnit.SECONDS.sleep(1); 55 | String info = "I'm " + i++ + "-th information from client"; 56 | info += Thread.currentThread().getName(); 57 | buffer.clear(); 58 | buffer.put(info.getBytes()); 59 | buffer.flip(); 60 | // Write()方法无法保证能写多少字节到SocketChannel。 61 | // 所以,重复调用write()直到Buffer没有要写的字节为止 62 | while (buffer.hasRemaining()) { 63 | System.out.println(buffer); 64 | socketChannel.write(buffer); 65 | } 66 | } 67 | } 68 | } catch (IOException | InterruptedException e) { 69 | e.printStackTrace(); 70 | } finally { 71 | try { 72 | if (socketChannel != null) { 73 | socketChannel.close(); 74 | } 75 | } catch (IOException e) { 76 | e.printStackTrace(); 77 | } 78 | } 79 | } 80 | 81 | /** 82 | * 传统IO方式实现的Server端 83 | */ 84 | public static void server() { 85 | ServerSocket serverSocket = null; 86 | InputStream in = null; 87 | try { 88 | // 创建Socket 89 | serverSocket = new ServerSocket(8080); 90 | int recvMsgSize = 0; 91 | byte[] recvBuf = new byte[1024]; 92 | while (true) {// 一直保持运行状态 93 | // 接受到消息 94 | Socket clntSocket = serverSocket.accept(); 95 | SocketAddress clientAddress = clntSocket.getRemoteSocketAddress(); 96 | System.out.println("Handling client at " + clientAddress); 97 | // 处理来自client的消息 98 | in = clntSocket.getInputStream(); 99 | while ((recvMsgSize = in.read(recvBuf)) != -1) { 100 | byte[] temp = new byte[recvMsgSize]; 101 | System.arraycopy(recvBuf, 0, temp, 0, recvMsgSize); 102 | System.out.println(new String(temp)); 103 | } 104 | } 105 | } catch (IOException e) { 106 | e.printStackTrace(); 107 | } finally { 108 | try { 109 | if (serverSocket != null) { 110 | serverSocket.close(); 111 | } 112 | if (in != null) { 113 | in.close(); 114 | } 115 | } catch (IOException e) { 116 | e.printStackTrace(); 117 | } 118 | } 119 | } 120 | } 121 | 122 | /** 123 | * NIO方式实现的Server端 124 | * 125 | * @author taomk 2017年8月8日 下午10:50:35 126 | * 127 | */ 128 | class ServerConnect { 129 | 130 | private static final int BUF_SIZE = 1024; 131 | private static final int PORT = 8080; 132 | private static final int TIMEOUT = 3000; 133 | 134 | public static void main(String[] args) { 135 | selector(); 136 | } 137 | 138 | public static void handleAccept(SelectionKey key) throws IOException { 139 | ServerSocketChannel ssChannel = (ServerSocketChannel) key.channel(); 140 | SocketChannel sc = ssChannel.accept(); 141 | sc.configureBlocking(false); 142 | sc.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocateDirect(BUF_SIZE)); 143 | } 144 | 145 | public static void handleRead(SelectionKey key) throws IOException { 146 | SocketChannel sc = (SocketChannel) key.channel(); 147 | ByteBuffer buf = (ByteBuffer) key.attachment(); 148 | long bytesRead = sc.read(buf); 149 | while (bytesRead > 0) { 150 | buf.flip(); 151 | while (buf.hasRemaining()) { 152 | System.out.print((char) buf.get()); 153 | } 154 | System.out.println(); 155 | buf.clear(); 156 | bytesRead = sc.read(buf); 157 | } 158 | if (bytesRead == -1) { 159 | sc.close(); 160 | } 161 | } 162 | 163 | public static void handleWrite(SelectionKey key) throws IOException { 164 | ByteBuffer buf = (ByteBuffer) key.attachment(); 165 | buf.flip(); 166 | SocketChannel sc = (SocketChannel) key.channel(); 167 | while (buf.hasRemaining()) { 168 | sc.write(buf); 169 | } 170 | buf.compact(); 171 | } 172 | 173 | public static void selector() { 174 | Selector selector = null; 175 | ServerSocketChannel ssc = null; 176 | try { 177 | // 打开Serlector 178 | selector = Selector.open(); 179 | // 打开ServerSocketChannel 180 | ssc = ServerSocketChannel.open(); 181 | // 绑定本机指定端口 182 | ssc.socket().bind(new InetSocketAddress(PORT)); 183 | // 非阻塞,channel在与selector配合使用时,必须是非阻塞状态 184 | ssc.configureBlocking(false); 185 | // 注册channel到selector,一旦有client与server接受就绪就会通知到selector 186 | ssc.register(selector, SelectionKey.OP_ACCEPT); 187 | 188 | while (true) {//一直保持活跃状态 189 | if (selector.select(TIMEOUT) == 0) { 190 | System.out.println("=="); 191 | continue; 192 | } 193 | Iterator iter = selector.selectedKeys().iterator(); 194 | while (iter.hasNext()) { 195 | SelectionKey key = iter.next(); 196 | if (key.isAcceptable()) { 197 | handleAccept(key); 198 | } 199 | if (key.isReadable()) { 200 | handleRead(key); 201 | } 202 | if (key.isWritable() && key.isValid()) { 203 | handleWrite(key); 204 | } 205 | if (key.isConnectable()) { 206 | System.out.println("isConnectable = true"); 207 | } 208 | iter.remove(); 209 | } 210 | } 211 | 212 | } catch (IOException e) { 213 | e.printStackTrace(); 214 | } finally { 215 | try { 216 | if (selector != null) { 217 | selector.close(); 218 | } 219 | if (ssc != null) { 220 | ssc.close(); 221 | } 222 | } catch (IOException e) { 223 | e.printStackTrace(); 224 | } 225 | } 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/oom/DirectMemoryOOM.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.oom; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | import sun.misc.Unsafe; 6 | 7 | /** 8 | *
 9 |  * 	使用unsafe分配本机内存
10 | * VM Args:-Xmx20M -XX:MaxDirectMemorySize=10M 11 | * 通过反射直接使用Unsafe类提供的allocateMemory()方法请求内存。 12 | *
13 | * 14 | * @author taomk 2016年11月7日 下午2 :24:44 15 | * 16 | */ 17 | @SuppressWarnings("restriction") 18 | public class DirectMemoryOOM { 19 | 20 | private static final int _1MB = 1024 * 1024; 21 | 22 | public static void main(String[] args) { 23 | Field unsafeField = Unsafe.class.getDeclaredFields()[0]; 24 | unsafeField.setAccessible(true); 25 | try { 26 | Unsafe unsafe = (Unsafe) unsafeField.get(null); 27 | while(true){ 28 | unsafe.allocateMemory(_1MB); 29 | } 30 | } catch (Exception e) { 31 | e.printStackTrace(); 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/oom/HeapOOM.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.oom; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Java堆内存溢出异常测试
8 | * VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError 9 | * @author taomk 2016年10月31日 下午8:40:02 10 | * 11 | */ 12 | public class HeapOOM { 13 | 14 | public static void main(String[] args) { 15 | List list = new ArrayList(); 16 | while(true){ 17 | list.add(new OOMObject()); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/oom/OOMObject.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.oom; 2 | 3 | /** 4 | * Java堆内存溢出异常测试
5 | * 6 | * @author taomk 2016年10月31日 下午8:43:27 7 | * 8 | */ 9 | public class OOMObject { 10 | 11 | public static void main(String[] args) { 12 | System.out.println("Hello"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/oom/RuntimeConstantPoolOOM.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.oom; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | *
 8 |  * 运行时常量池导致的内存溢出异常
9 | * VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M
10 | * Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=10M; support was removed in 8.0 11 | * Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=10M; support was removed in 8.0 12 | *
13 | * @author taomk 2016年11月3日 上午10:57:11 14 | * 15 | */ 16 | public class RuntimeConstantPoolOOM { 17 | 18 | public static void main(String[] args) { 19 | // 使用List保持着常量池引用,避免Full GC回收常量池行为 20 | List list = new ArrayList(); 21 | // 10MB的PermSize在integer范围内足够产生OOM了 22 | int i = 0; 23 | while (true) { 24 | list.add(String.valueOf(i++).intern()); 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/oom/Test.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.oom; 2 | 3 | /** 4 | * @author taomk 2017年3月6日 下午7:13:29 5 | * 6 | */ 7 | public class Test { 8 | 9 | public static void main(String[] args) { 10 | 11 | Integer i1 = 123; 12 | Integer i2 = 123; 13 | Integer i3 = new Integer(123); 14 | Integer i4 = 128; 15 | Integer i5 = 128; 16 | 17 | int i6 = 123; 18 | int i7 = 1234; 19 | 20 | System.out.println(i1 == i2); 21 | System.out.println(i1.equals(i2)); 22 | 23 | System.out.println(i1 == i3); 24 | System.out.println(i1.equals(i3)); 25 | 26 | System.out.println(i1 == i6); 27 | System.out.println(i1.equals(i6)); 28 | 29 | System.out.println(i4 == i5); 30 | System.out.println(i4.equals(i5)); 31 | 32 | 33 | System.out.println(i3 == i7); 34 | // System.out.println(i5.equals(i4)); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/proxy/Client.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.proxy; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Proxy; 5 | 6 | /** 7 | * 客户端-测试类 8 | * 9 | * @author taomk 2017年3月22日 下午4:02:12 10 | * 11 | */ 12 | public class Client { 13 | 14 | public static void main(String[] args) { 15 | 16 | // 要代理的真实对象 17 | Subject realSubject = new SubjectImpl(); 18 | 19 | // 通过真实对象来调用其方法 20 | InvocationHandler handler = new DynamicProxy(realSubject); 21 | 22 | Subject proxySubject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), 23 | // realSubject.getClass().getInterfaces(), 24 | new Class[]{Subject.class}, 25 | handler); 26 | 27 | System.out.println(proxySubject.getClass().getName()); 28 | System.out.println(); 29 | 30 | proxySubject.sayHello("taomk"); 31 | System.out.println(); 32 | 33 | proxySubject.wish(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/proxy/DynamicProxy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.proxy; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Method; 5 | 6 | /** 7 | * proxy study 8 | * @author taomk 2017年3月22日 下午3:55:28 9 | * 10 | */ 11 | public class DynamicProxy implements InvocationHandler { 12 | 13 | /** 14 | * 被代理对象 15 | */ 16 | private Object target; 17 | 18 | DynamicProxy(Object subject){ 19 | this.target = subject; 20 | } 21 | 22 | /* (non-Javadoc) 23 | * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) 24 | */ 25 | @Override 26 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 27 | 28 | System.out.println("proxy : " + proxy.getClass().getName()); 29 | 30 | System.out.println("Before saying my wish..."); 31 | 32 | System.out.println("Method : " + method); 33 | 34 | method.invoke(target, args); 35 | 36 | System.out.println("Thank you, that's the end of my speech."); 37 | 38 | return null; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/proxy/Subject.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.proxy; 2 | 3 | /** 4 | * proxy study 5 | * 被代理对象-接口定义 6 | * @author taomk 2017年3月22日 下午3:49:58 7 | * 8 | */ 9 | public interface Subject { 10 | 11 | default void a(){} 12 | 13 | default void b(){} 14 | 15 | public void wish(); 16 | 17 | public void sayHello(String myName); 18 | } 19 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/proxy/SubjectImpl.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.proxy; 2 | 3 | /** 4 | * 被代理对象-实现类 5 | * @author taomk 2017年3月22日 下午3:52:20 6 | * 7 | */ 8 | public class SubjectImpl implements Subject { 9 | 10 | /* (non-Javadoc) 11 | * @see com.taomk.understandingJVM.proxy.Sublect#rent() 12 | */ 13 | @Override 14 | public void wish() { 15 | 16 | System.out.println("I wish a big house in beijing. "); 17 | } 18 | 19 | /* (non-Javadoc) 20 | * @see com.taomk.understandingJVM.proxy.Sublect#sayHello(java.lang.String) 21 | */ 22 | @Override 23 | public void sayHello(String myName) { 24 | System.out.println("Hi, everyone. My name is " + myName); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/sort/QuickSort.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.sort; 2 | 3 | /** 4 | * 快速排序 5 | * 6 | * @author taomk 2017年3月16日 上午11:03:18 7 | * 8 | */ 9 | public class QuickSort { 10 | 11 | public static void main(String[] args) { 12 | 13 | int[] array = {3,5,7,9,13,2,4,6,7,1,7,16,18}; 14 | 15 | array = sort(array, 0, array.length-1); 16 | 17 | for (int i = 0; i < array.length; i++) { 18 | System.out.print(array[i] + " , "); 19 | } 20 | } 21 | 22 | public static int partition(int[] array, int lo, int hi) { 23 | 24 | // 固定的切分方式 25 | int key = array[lo]; 26 | while (lo < hi) { 27 | while (array[hi] >= key && hi > lo) {// 从后半部分向前扫描 28 | hi--; 29 | } 30 | array[lo] = array[hi]; 31 | while (array[lo] <= key && hi > lo) {// 从前半部分向后扫描 32 | lo++; 33 | } 34 | array[hi] = array[lo]; 35 | } 36 | array[hi] = key; 37 | return hi; 38 | } 39 | 40 | public static int[] sort(int[] array, int lo, int hi) { 41 | 42 | if (lo >= hi) { 43 | return null; 44 | } 45 | 46 | int index = partition(array, lo, hi); 47 | 48 | sort(array, lo, index - 1); 49 | 50 | sort(array, index + 1, hi); 51 | 52 | return array; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/stream/StreamTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.stream; 2 | 3 | import java.util.Arrays; 4 | import java.util.Comparator; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | 8 | /** 9 | * http://www.importnew.com/26090.html 10 | * 11 | * @author taomk 2017年8月9日 上午10:51:52 12 | * 13 | */ 14 | public class StreamTest { 15 | 16 | public static void main(String[] args) { 17 | 18 | List stores = init(); 19 | 20 | // 使用了lambda表达式来完成,如果使用传统的集合方式的话,会更加冗长 21 | // Collections.sort(stores, (x,y)->x.distance.compareTo(y.distance)); 22 | // String choosedStoreName = stores.get(0).getName(); 23 | 24 | // 效率更好的解决方式,使用stream 25 | String choosedStoreName = stores 26 | .stream() 27 | .sorted(Comparator.comparingInt(s -> s.distance)) 28 | .findFirst() 29 | .get() 30 | .getName(); 31 | 32 | System.out.println("选择距离自己最近的一家店铺点菜 , 这家店铺的名称是:" + choosedStoreName); 33 | 34 | long hotSotreCount = stores.stream().filter(p -> p.salesCount > 1000).count(); 35 | System.out.println("月销量超过1000,销售火爆的店铺数量是:" + hotSotreCount); 36 | 37 | StoreProperty s = stores.stream().min(Comparator.comparingInt(p->p.priceLevel)).get(); 38 | System.out.println("价格最低的那家店铺是:" + s.getName()); 39 | 40 | List nearestStores = stores.stream().sorted(Comparator.comparingInt(p -> p.distance)).limit(2).collect(Collectors.toList()); 41 | System.out.println("距离最近的两家店铺是:"); 42 | nearestStores.forEach(p -> System.out.println("\t" + p.name )); 43 | 44 | List names = stores.parallelStream() 45 | .filter(p -> p.priceLevel<30) 46 | .sorted(Comparator.comparingInt(StoreProperty::getDistance)) 47 | .limit(3) 48 | .map(StoreProperty::getName) 49 | .collect(Collectors.toList()); 50 | System.out.println("筛选出价格低于30,按照距离排序的3家店铺是:"); 51 | names.forEach(p -> System.out.println("\t" + p)); 52 | } 53 | 54 | /** 55 | * 初始化4家店铺 56 | * 57 | * @return 58 | */ 59 | private static List init(){ 60 | StoreProperty s1 = new StoreProperty("叫了个鸡", 1000, 500, 28); 61 | StoreProperty s2 = new StoreProperty("张三丰饺子馆", 2300, 1500, 25); 62 | StoreProperty s3 = new StoreProperty("永和大王", 580, 3000, 32); 63 | StoreProperty s4 = new StoreProperty("肯德基", 6000, 200, 26); 64 | 65 | return Arrays.asList(s1,s2,s3,s4); 66 | } 67 | } 68 | 69 | /** 70 | * 店铺属性 71 | * 72 | * @author taomk 2017年8月9日 上午10:54:30 73 | * 74 | */ 75 | class StoreProperty { 76 | 77 | /** 78 | * 店铺名称 79 | */ 80 | String name; 81 | /** 82 | * 距离(单位:米) 83 | */ 84 | Integer distance; 85 | /** 86 | * 销量(月售) 87 | */ 88 | Integer salesCount; 89 | /** 90 | * 价格(元) 91 | */ 92 | Integer priceLevel; 93 | 94 | public StoreProperty(String name, Integer distance, Integer salesCount, Integer priceLevel) { 95 | super(); 96 | this.name = name; 97 | this.distance = distance; 98 | this.salesCount = salesCount; 99 | this.priceLevel = priceLevel; 100 | } 101 | 102 | public String getName() { 103 | return name; 104 | } 105 | public void setName(String name) { 106 | this.name = name; 107 | } 108 | public Integer getDistance() { 109 | return distance; 110 | } 111 | public void setDistance(Integer distance) { 112 | this.distance = distance; 113 | } 114 | public Integer getSalesCount() { 115 | return salesCount; 116 | } 117 | public void setSalesCount(Integer salesCount) { 118 | this.salesCount = salesCount; 119 | } 120 | public Integer getPriceLevel() { 121 | return priceLevel; 122 | } 123 | public void setPriceLevel(Integer priceLevel) { 124 | this.priceLevel = priceLevel; 125 | } 126 | 127 | } -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/task/FutureTaskTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.task; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.Callable; 6 | import java.util.concurrent.ExecutionException; 7 | import java.util.concurrent.ExecutorService; 8 | import java.util.concurrent.Executors; 9 | import java.util.concurrent.FutureTask; 10 | 11 | /** 12 | * FutureTask Study 13 | * 14 | * @author taomk 2017年5月16日 下午9:55:40 15 | * 16 | */ 17 | public class FutureTaskTest { 18 | 19 | public static void main(String[] args) { 20 | 21 | // 创建任务集合 22 | List> taskList = new ArrayList>(); 23 | 24 | // 创建线程池 25 | ExecutorService exec = Executors.newFixedThreadPool(5); 26 | 27 | for (int i = 0; i < 10; i++) { 28 | // 传入Callable对象创建FutureTask对象 29 | FutureTask ft = new FutureTask(new ComputeTask(i, "" + i)); 30 | taskList.add(ft); 31 | // 提交给线程池执行任务,也可以通过exec.invokeAll(taskList)一次性提交所有任务; 32 | exec.submit(ft); 33 | } 34 | 35 | System.out.println("所有计算任务提交完毕, 主线程接着干其他事情!" + Thread.currentThread().getName()); 36 | 37 | // 开始统计各计算线程计算结果 38 | Integer totalResult = 0; 39 | for (FutureTask ft : taskList) { 40 | try { 41 | // FutureTask的get方法会自动阻塞,直到获取计算结果为止 42 | totalResult = totalResult + ft.get(); 43 | } catch (InterruptedException e) { 44 | e.printStackTrace(); 45 | } catch (ExecutionException e) { 46 | e.printStackTrace(); 47 | } 48 | } 49 | 50 | // 关闭线程池 51 | exec.shutdown(); 52 | System.out.println("多任务计算后的总结果是:" + totalResult); 53 | System.out.println("主线程运行结束!" + Thread.currentThread().getName()); 54 | } 55 | 56 | } 57 | 58 | class ComputeTask implements Callable { 59 | 60 | private Integer result = 0; 61 | private String taskName = ""; 62 | 63 | public ComputeTask(Integer iniResult, String taskName) { 64 | result = iniResult; 65 | this.taskName = taskName; 66 | System.out.println("生成子线程计算任务: " + taskName); 67 | } 68 | 69 | public String getTaskName() { 70 | return this.taskName; 71 | } 72 | 73 | @Override 74 | public Integer call() throws Exception { 75 | for (int i = 0; i < 100; i++) { 76 | result = +i; 77 | } 78 | // 休眠5秒钟,观察主线程行为,预期的结果是主线程会继续执行,到要取得FutureTask的结果等待直至完成。 79 | Thread.sleep(1000*3); 80 | System.out.println("子线程计算任务: " + taskName + " 执行完成!当前结果为:" + result); 81 | return result; 82 | } 83 | } -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/task/RunnableFutureTaskTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.task; 2 | 3 | import java.util.concurrent.Callable; 4 | import java.util.concurrent.ExecutionException; 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.Future; 8 | import java.util.concurrent.FutureTask; 9 | 10 | /** 11 | * 12 | * http://blog.csdn.net/bboyfeiyu/article/details/24851847 13 | * 14 | * @author taomk 2017年8月29日 下午2:28:31 15 | * 16 | */ 17 | public class RunnableFutureTaskTest { 18 | 19 | static ExecutorService fixedService = Executors.newSingleThreadExecutor(); 20 | 21 | public static void main(String[] args) { 22 | 23 | runnableDemo(); 24 | try { 25 | futureDemo(); 26 | callableDemo(); 27 | futureTaskDemo(); 28 | } catch (InterruptedException e) { 29 | e.printStackTrace(); 30 | } catch (ExecutionException e) { 31 | e.printStackTrace(); 32 | } 33 | 34 | } 35 | 36 | /** 37 | * 实现runnable接口的方式,无法直接获取返回值 38 | */ 39 | static void runnableDemo() { 40 | new Thread(() -> System.out.println("runnable demo result : " + fibrc(20))).start(); 41 | } 42 | 43 | /** 44 | * 向ExecutorService 提交runnable则没有返回值, future没有数据 45 | * 46 | * @throws InterruptedException 47 | * @throws ExecutionException 48 | */ 49 | static void futureDemo() throws InterruptedException, ExecutionException { 50 | Future futureResult = fixedService.submit(new Runnable() { 51 | 52 | @Override 53 | public void run() { 54 | fibrc(20); 55 | } 56 | 57 | }); 58 | System.out.println("future demo result : " + futureResult.get()); 59 | } 60 | 61 | /** 62 | * 向ExecutorService 提交callable则没有返回值, future有数据 63 | * 64 | * @throws InterruptedException 65 | * @throws ExecutionException 66 | */ 67 | static void callableDemo() throws InterruptedException, ExecutionException { 68 | Future futureResult = fixedService.submit(new Callable() { 69 | 70 | @Override 71 | public Integer call() throws Exception { 72 | return fibrc(20); 73 | } 74 | 75 | }); 76 | System.out.println("callable demo result : " + futureResult.get()); 77 | } 78 | 79 | static void futureTaskDemo() throws InterruptedException, ExecutionException { 80 | FutureTask futureTask = new FutureTask(new Callable() { 81 | 82 | @Override 83 | public Integer call() throws Exception { 84 | return fibrc(20); 85 | } 86 | 87 | }); 88 | 89 | fixedService.submit(futureTask); 90 | System.out.println("futureTask demo result : " + futureTask.get()); 91 | } 92 | 93 | /** 94 | * 计算斐波那契数列 95 | * 96 | * @param num 97 | * @return 98 | */ 99 | static int fibrc(int num) { 100 | 101 | if(num==0 || num==1) { 102 | return num; 103 | } 104 | 105 | return fibrc(num-1) + fibrc(num-2); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/thread/InterruptTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.thread; 2 | 3 | /** 4 | * 测试 Thread.interrupt() 方法 5 | * 6 | * @see Thread#interrupt() 7 | * 8 | * @author taomk 2017年6月16日 上午9:49:41 9 | * 10 | */ 11 | public class InterruptTest { 12 | 13 | public static void main(String[] args) { 14 | Thread clientThread = new Thread(new ClientThread(), "clientThread"); 15 | // 启动线程 16 | clientThread.start(); 17 | 18 | // interrupt线程 19 | clientThread.interrupt(); 20 | } 21 | 22 | } 23 | 24 | /** 25 | * 业务线程 26 | * 27 | * @author taomk 2017年6月16日 上午9:56:09 28 | * 29 | */ 30 | class ClientThread implements Runnable { 31 | 32 | @Override 33 | public void run() { 34 | 35 | System.out.println(Thread.currentThread().getName() + " running..."); 36 | 37 | try { 38 | Thread.sleep(10_1000); 39 | } catch (InterruptedException e) { 40 | e.printStackTrace(); 41 | System.err.println(Thread.currentThread().getName() + " interrupted..."); 42 | System.err.println(Thread.currentThread().getName() + " cause : " + e.getMessage()); 43 | } 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/thread/JoinDemo.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.thread; 2 | 3 | /** 4 | * http://blog.csdn.net/javazejian/article/details/50878665 5 | * 6 | * @author taomk 2017年6月21日 下午3:41:51 7 | * 8 | */ 9 | public class JoinDemo { 10 | 11 | 12 | public static void main(String[] args) { 13 | Thread previousThread = Thread.currentThread(); 14 | for (int i = 0; i < 10; i++) { 15 | Thread t = new Thread(new Domino(previousThread), i+""); 16 | t.start(); 17 | previousThread = t; 18 | } 19 | System.out.println(Thread.currentThread().getName() + "线程执行结束。"); 20 | } 21 | } 22 | 23 | class Domino implements Runnable{ 24 | 25 | private Thread thread; 26 | Domino(Thread t){ 27 | this.thread = t; 28 | } 29 | 30 | @Override 31 | public void run() { 32 | 33 | try { 34 | thread.join(); 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | } 38 | 39 | System.out.println(Thread.currentThread().getName() + "线程执行结束。"); 40 | 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/thread/JoinTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.thread; 2 | 3 | /** 4 | * 测试 Thread.join() 方法 5 | * 6 | * @see Thread#join() 7 | * 8 | * @author taomk 2017年6月16日 上午9:49:41 9 | * 10 | */ 11 | public class JoinTest { 12 | 13 | public static void main(String[] args) { 14 | Thread clientThread = new Thread(new ClientThread2(), "clientThread2"); 15 | // 启动线程 16 | clientThread.start(); 17 | 18 | // join线程 19 | try { 20 | clientThread.join(); 21 | } catch (InterruptedException e) { 22 | e.printStackTrace(); 23 | } 24 | 25 | System.out.println(Thread.currentThread().getName() + " terminated..."); 26 | } 27 | 28 | } 29 | 30 | /** 31 | * 业务线程 32 | * 33 | * @author taomk 2017年6月16日 上午9:56:09 34 | * 35 | */ 36 | class ClientThread2 implements Runnable { 37 | 38 | @Override 39 | public void run() { 40 | 41 | System.out.println(Thread.currentThread().getName() + " running..."); 42 | 43 | try { 44 | 45 | for (int i = 1; i <= 10; i++) { 46 | System.out.println(Thread.currentThread().getName() + " sleeping(s)..." + i); 47 | Thread.sleep(1000); 48 | } 49 | 50 | } catch (InterruptedException e) { 51 | e.printStackTrace(); 52 | System.err.println(Thread.currentThread().getName() + " interrupted..."); 53 | System.err.println(Thread.currentThread().getName() + " cause : " + e.getMessage()); 54 | } 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/thread/ThreadLocalTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.thread; 2 | 3 | /** 4 | * http://blog.csdn.net/hudashi/article/details/7076880 5 | * 6 | * @author taomk 2017年10月10日 下午2:14:57 7 | * 8 | */ 9 | public class ThreadLocalTest { 10 | 11 | public ThreadLocalTest() { 12 | // do nothing 13 | } 14 | 15 | ThreadLocal tl = new ThreadLocal(); 16 | 17 | void start() { 18 | System.out.println("begin"); 19 | Content content = tl.get(); 20 | if (content == null) { 21 | content = new Content(); 22 | tl.set(content); 23 | } 24 | 25 | System.out.println("try to release content data"); 26 | // tl.set(null);//@1 27 | // tl.remove();//@2 28 | 29 | tl = null;// @3 30 | content = null;// @4 31 | 32 | System.out.println("request gc"); 33 | System.gc(); 34 | 35 | try { 36 | Thread.sleep(1000); 37 | } catch (InterruptedException e) { 38 | e.printStackTrace(); 39 | } 40 | System.out.println("end"); 41 | } 42 | } 43 | 44 | class Content { 45 | 46 | // 10M 47 | byte data[] = new byte[1024 * 1024 * 10]; 48 | 49 | protected void finalize() { 50 | System.out.println("I am released"); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/thread/WaitTest.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.thread; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * 7 | * http://www.jasongj.com/java/multi_thread/ 8 | * 9 | * @author taomk 2017年9月29日 上午9:55:28 10 | * 11 | */ 12 | public class WaitTest { 13 | 14 | public static void main(String[] args) { 15 | 16 | Thread thread1 = new Thread(() -> { 17 | synchronized (WaitTest.class) { 18 | try { 19 | System.out.println(new Date() + " Thread1 is running"); 20 | 21 | // wait for notify 22 | WaitTest.class.wait(); 23 | System.out.println(new Date() + " Thread1 ended"); 24 | } catch (Exception ex) { 25 | ex.printStackTrace(); 26 | } 27 | } 28 | }); 29 | thread1.start(); 30 | 31 | Thread thread2 = new Thread(() -> { 32 | synchronized (WaitTest.class) { 33 | try { 34 | System.out.println(new Date() + " Thread2 is running"); 35 | WaitTest.class.notify(); 36 | // Don't use sleep method to avoid confusing 37 | for (long i = 0; i < 200000; i++) { 38 | for (long j = 0; j < 100000; j++) { 39 | } 40 | } 41 | System.out.println(new Date() + " Thread2 release lock"); 42 | } catch (Exception ex) { 43 | ex.printStackTrace(); 44 | } 45 | } 46 | 47 | for (long i = 0; i < 200000; i++) { 48 | for (long j = 0; j < 100000; j++) { 49 | } 50 | } 51 | System.out.println(new Date() + " Thread2 ended"); 52 | }); 53 | 54 | // Don't use sleep method to avoid confusing 55 | for (long i = 0; i < 200000; i++) { 56 | for (long j = 0; j < 100000; j++) { 57 | } 58 | } 59 | thread2.start(); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/tree/BinaryTreeStudy.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.tree; 2 | 3 | /** 4 | * 二叉树study 5 | * 6 | *
  7 |  *           A 
  8 |  *     B          C 
  9 |  *  D     E            F
 10 |  * 
11 | * @author taomk 2017年3月6日 下午2:59:02 12 | * 13 | */ 14 | public class BinaryTreeStudy { 15 | 16 | /** 17 | * 根节点 18 | */ 19 | private TreeNode rootNode; 20 | 21 | BinaryTreeStudy() { 22 | rootNode = new TreeNode(1, "rootNode(A)"); 23 | } 24 | 25 | public TreeNode getRootNode() { 26 | return rootNode; 27 | } 28 | 29 | public void setRootNode(TreeNode rootNode) { 30 | this.rootNode = rootNode; 31 | } 32 | 33 | public static void main(String[] args) { 34 | 35 | BinaryTreeStudy binaryTree = new BinaryTreeStudy(); 36 | binaryTree.createBinaryTreeNode(binaryTree.getRootNode()); 37 | 38 | System.out.println("The size of the tree is " + binaryTree.size()); 39 | System.out.println("The height of the tree is " + binaryTree.height()); 40 | 41 | System.out.println("*******(前序遍历)[ABDECF]遍历*****************"); 42 | binaryTree.preOrder(binaryTree.getRootNode()); 43 | 44 | System.out.println("*******(中序遍历)[DBEACF]遍历*****************"); 45 | binaryTree.inOrder(binaryTree.getRootNode()); 46 | 47 | System.out.println("*******(后序遍历)[DEBFCA]遍历*****************"); 48 | binaryTree.postOrder(binaryTree.getRootNode()); 49 | 50 | // System.out.println("***非递归实现****(前序遍历)[ABDECF]遍历*****************"); 51 | // binaryTree.nonRecPreOrder(binaryTree.getRootNode()); 52 | // 53 | // System.out.println("***非递归实现****(中序遍历)[DBEACF]遍历*****************"); 54 | // binaryTree.nonRecInOrder(binaryTree.getRootNode()); 55 | // 56 | // System.out.println("***非递归实现****(后序遍历)[DEBFCA]遍历*****************"); 57 | // binaryTree.noRecPostOrder(binaryTree.getRootNode()); 58 | 59 | } 60 | 61 | /** 62 | * 检查二叉树是否为空 63 | * 64 | * @return 65 | */ 66 | public boolean isEmpty() { 67 | return rootNode == null; 68 | } 69 | 70 | /** 71 | * 返回树的高度 72 | * 73 | * @return 74 | */ 75 | public int height() { 76 | return height(rootNode); 77 | } 78 | 79 | /** 80 | * 返回树的节点个数 81 | * 82 | * @return 83 | */ 84 | public int size() { 85 | return size(rootNode); 86 | } 87 | 88 | /** 89 | * 返回元素的父节点 90 | * 91 | * @param element 92 | * @return 93 | */ 94 | TreeNode parent(TreeNode element) { 95 | if (rootNode == null || element == rootNode) { 96 | return null; 97 | } else { 98 | return parent(rootNode, element); 99 | } 100 | } 101 | 102 | /** 103 | * 查找左子树 104 | * 105 | * @param element 106 | * @return 107 | */ 108 | public TreeNode getLeftChildNode(TreeNode element) { 109 | return (element != null) ? element.getLeftTreeNode() : null; 110 | } 111 | 112 | /** 113 | * 查找右子树 114 | * 115 | * @param element 116 | * @return 117 | */ 118 | public TreeNode getRightChildNode(TreeNode element) { 119 | return (element != null) ? element.getRightTreeNode() : null; 120 | } 121 | 122 | /** 123 | * 返回根节点 124 | * 125 | * @return 126 | */ 127 | public TreeNode getRoot() { 128 | return rootNode; 129 | } 130 | 131 | /** 132 | * 释放节点 133 | * 134 | * @param subTree 135 | */ 136 | public void destory(TreeNode subTree) { 137 | if (subTree != null) { 138 | destory(subTree.getLeftTreeNode()); 139 | destory(subTree.getRightTreeNode()); 140 | subTree = null; 141 | } 142 | } 143 | 144 | /** 145 | * 遍历 146 | * 147 | * @param subTree 148 | */ 149 | public void traverse(TreeNode subTree) { 150 | System.out.println("key:" + subTree.getKey() + "-data:" + subTree.getData()); 151 | traverse(subTree.getLeftTreeNode()); 152 | traverse(subTree.getRightTreeNode()); 153 | } 154 | 155 | /** 156 | * 前序遍历 157 | * 158 | * @param subTree 159 | */ 160 | public void preOrder(TreeNode subTree) { 161 | if (subTree != null) { 162 | visted(subTree); 163 | preOrder(subTree.getLeftTreeNode()); 164 | preOrder(subTree.getRightTreeNode()); 165 | } 166 | } 167 | 168 | /** 169 | * 中序遍历 170 | * 171 | * @param subTree 172 | */ 173 | public void inOrder(TreeNode subTree) { 174 | if (subTree != null) { 175 | inOrder(subTree.getLeftTreeNode()); 176 | visted(subTree); 177 | inOrder(subTree.getRightTreeNode()); 178 | } 179 | } 180 | 181 | /** 182 | * 后续遍历 183 | * 184 | * @param subTree 185 | */ 186 | public void postOrder(TreeNode subTree) { 187 | if (subTree != null) { 188 | postOrder(subTree.getLeftTreeNode()); 189 | postOrder(subTree.getRightTreeNode()); 190 | visted(subTree); 191 | } 192 | } 193 | 194 | private void visted(TreeNode subTree){ 195 | subTree.setVisited(true); 196 | System.out.println("key:"+subTree.getKey()+"-data:"+subTree.getData());; 197 | } 198 | 199 | private TreeNode parent(TreeNode subTree, TreeNode element) { 200 | if (subTree == null) { 201 | return null; 202 | } else if (subTree.getLeftTreeNode() == element || subTree.getRightTreeNode() == element) { 203 | // 返回父结点地址 204 | return subTree; 205 | } 206 | 207 | TreeNode p; 208 | // 先在左子树中找,如果左子树中没有找到,才到右子树去找 209 | if ((p = parent(subTree.getLeftTreeNode(), element)) != null) { 210 | // 递归在左子树中搜索 211 | return p; 212 | } else { 213 | // 递归在右子树中搜索 214 | return parent(subTree.getRightTreeNode(), element); 215 | } 216 | } 217 | 218 | /** 219 | * 递归遍历计算出二叉树节点个数 220 | * 221 | * @param subNode 222 | * @return 223 | */ 224 | private int size(TreeNode subNode) { 225 | if (subNode == null) { 226 | return 0; 227 | } else { 228 | return size(subNode.getLeftTreeNode()) + size(subNode.getRightTreeNode()) + 1; 229 | } 230 | } 231 | 232 | /** 233 | * 递归遍历计算出二叉树的高度 234 | * 235 | * @param subNode 236 | * @return 237 | */ 238 | private int height(TreeNode subNode) { 239 | 240 | if (subNode == null) { 241 | return 0; 242 | } else { 243 | int leftNodeHeight = height(subNode.getLeftTreeNode()); 244 | int rightNodeHeight = height(subNode.getRightTreeNode()); 245 | return (leftNodeHeight > rightNodeHeight) ? (leftNodeHeight + 1) : (rightNodeHeight + 1); 246 | } 247 | } 248 | 249 | /** 250 | * 创建一棵如下结构的二叉树。 251 | * 252 | *
253 | 	 *           A 
254 | 	 *     B          C 
255 | 	 *  D     E            F
256 | 	 * 
257 | * 258 | * 259 | * @param root 260 | * 根节点 261 | */ 262 | public void createBinaryTreeNode(TreeNode root) { 263 | 264 | TreeNode nodeB = new TreeNode(2, "B"); 265 | TreeNode nodeC = new TreeNode(3, "C"); 266 | TreeNode nodeD = new TreeNode(4, "D"); 267 | TreeNode nodeE = new TreeNode(5, "E"); 268 | TreeNode nodeF = new TreeNode(6, "F"); 269 | 270 | root.setLeftTreeNode(nodeB); 271 | root.setRightTreeNode(nodeC); 272 | 273 | root.getLeftTreeNode().setLeftTreeNode(nodeD); 274 | root.getLeftTreeNode().setRightTreeNode(nodeE); 275 | root.getRightTreeNode().setRightTreeNode(nodeF); 276 | } 277 | 278 | } 279 | 280 | /** 281 | * 定义一棵二叉树 282 | * 283 | * @author taomk 2017年3月6日 下午3:05:17 284 | * 285 | */ 286 | class TreeNode { 287 | private int key = 0; 288 | private String data; 289 | private boolean isVisited = false; 290 | private TreeNode leftTreeNode; 291 | private TreeNode rightTreeNode; 292 | 293 | public TreeNode() { 294 | // Empty 295 | } 296 | 297 | public TreeNode(int key, String data) { 298 | this.key = key; 299 | this.data = data; 300 | leftTreeNode = null; 301 | rightTreeNode = null; 302 | } 303 | 304 | public int getKey() { 305 | return key; 306 | } 307 | 308 | public void setKey(int key) { 309 | this.key = key; 310 | } 311 | 312 | public String getData() { 313 | return data; 314 | } 315 | 316 | public void setData(String data) { 317 | this.data = data; 318 | } 319 | 320 | public boolean isVisited() { 321 | return isVisited; 322 | } 323 | 324 | public void setVisited(boolean isVisited) { 325 | this.isVisited = isVisited; 326 | } 327 | 328 | public TreeNode getLeftTreeNode() { 329 | return leftTreeNode; 330 | } 331 | 332 | public void setLeftTreeNode(TreeNode leftTreeNode) { 333 | this.leftTreeNode = leftTreeNode; 334 | } 335 | 336 | public TreeNode getRightTreeNode() { 337 | return rightTreeNode; 338 | } 339 | 340 | public void setRightTreeNode(TreeNode rightTreeNode) { 341 | this.rightTreeNode = rightTreeNode; 342 | } 343 | 344 | } 345 | -------------------------------------------------------------------------------- /src/com/taomk/understandingJVM/visibility/VisibilityThred.java: -------------------------------------------------------------------------------- 1 | package com.taomk.understandingJVM.visibility; 2 | 3 | /** 4 | *
 5 |  *  测试线程可见性问题
 6 |  *  http://ifeve.com/concurrency-visibility/
 7 |  *  
8 | * 9 | * @author taomk 2017年5月24日 下午9:58:33 10 | * 11 | */ 12 | public class VisibilityThred extends Thread{ 13 | 14 | // 注意比较变量加volatile关键字前后的区别 15 | // private boolean stop = false; 16 | private volatile boolean stop = false; 17 | 18 | @Override 19 | public void run() { 20 | int count = 0; 21 | System.out.println("开始计数:" + count); 22 | while(!stop){ 23 | count++; 24 | } 25 | System.out.println("结束计数:" + count); 26 | } 27 | 28 | /** 29 | * 停止计数 30 | */ 31 | public void stopCount(){ 32 | this.stop = true; 33 | } 34 | 35 | /** 36 | * @return true-已停止计数;false-未停止计数 37 | */ 38 | public boolean isStop(){ 39 | return stop; 40 | } 41 | 42 | public static void main(String[] args) throws InterruptedException { 43 | 44 | VisibilityThred t = new VisibilityThred(); 45 | t.start(); 46 | 47 | // 确保测试线程已启动 48 | Thread.sleep(1000); 49 | 50 | t.stopCount(); 51 | 52 | // 确保测试线程执行完毕 53 | Thread.sleep(1000); 54 | 55 | System.out.println("计数线程中的stop值为:" + t.isStop()); 56 | 57 | } 58 | 59 | } 60 | --------------------------------------------------------------------------------