Java Instrument

作用 Java Instrument指的是可以用独立于应用程序之外的代理程序来监测和协助运行在JVM上的应用程序,包括但不限于获取JVM运行时状态,替换和修改类定义。 使用方法 Java SE5及以后的版本,可以在一个普通Java程序运行时,通过-javaagent参数制定一个特定的jar文件(包含Instrumentation代理)来启动Instrumentation的代理程序。 代理类必须提供一个public static void premain(String args, Instrumentation inst) ...

虚假唤醒(spurious wankeups)

典型案例:在wait端必须用while来等待条件变量而不能用if。 // wait端 pthread_mutex_lock(mtx); while(deque.empty()) pthread_cond_wait(...); deque.pop_front(); pthread_mutex_unlock(mtx) ...

一个线程两次调用start()方法会出现什么情况? - 《java核心技术》笔记

java的线程不允许启动两次,第二次调用会抛出IllegalThreadStateException,是一种运行时异常。 线程间状态流转: 就绪:该线程已经在JVM,可能正在运行,也可能正在等待系统分配给它CPU时间片,在就绪队列中排队; 阻塞:等待monitor lock; 等待:正在等待其他线程采取某些操作,比如消费者模式。 需要注意的一些点: 守护线程必须在线程启动之前设置 Thread daemonThread = new ...

java多线程(5) - Java虚拟机中的锁优化技术以及几种锁的介绍

线程的五种状态: 自旋锁 在程序中,Java虚拟机的开发工程师们在分析过大量数据后发现,共享数据的锁定状态一般只会持续很短的一段时间,为了这段时间去挂起和恢复线程其实并不值得。 如果物理机上有多个处理器,可以让多个线程同时执行的话,就可以让后来的线程“稍微(忙)等一下”,不会放弃处理器事件,看看持有锁的线程会不会很快释放锁。这个“稍微等一下”的过程就是自旋。 锁消除 在动态编译同步块的时候,JIT编译器可以借助一种叫逃逸分析( ...

java多线程(4) - Moniter的实现原理

Moniter是什么 我们可以把监视器理解为包含一个特殊的房间的建筑物,这个特殊房间同一时刻只能有一个客人。如果一个顾客想要进去这个房间,就需要在走廊(Entry Set)排队,调度器将基于某个标准来选择排队的客户进入房间。如果用户暂时因为其他事情无法脱身,那么就会被送到等待室(Wait Set)。 监视器是一个用来监视这些线程进入特殊的房间的,它的义务是保证(同一时刻)只有一个线程可以访问被保护的数据和代码。 Monitor其实是一种同步机制,通常被描述为一个对象,其主要特点是: ...

java多线程(3) - java的对象头

回顾 当一个Java类在被JVM加载后,JVM会给这个类创建一个instanceKlass,保存在方法区,用于在JVM层表示该Java类。 当我们在代码中new一个对象时,JVM会创建一个instanceOopDesc对象,包含了对象头以及实例数据。 对象头包括: class oopDesc { friend class VMStructs; private: volatile markOop _mark; union _metadata ...

java多线程(2) - Java的对象模型

java对象保存在堆内存中。在内存中,一个Java对象包含三部分:对象头、实例数据和对象填充。 对象头中包含锁状态标志、线程持有的锁等标志。 Java的对象模型 在JVM的内存结构中,对象保存在堆内存中。我们在对对象进行操作时,操作的是对象的引用。 那么对象本身在JVM中的结构是什么样的? oop-klass model HotSpot JVM的设计者不想让每个对象中都含有一个vtable(虚函数表)(HotSpot基于C++实现) ...

管程

作用 管程保证了同一时间只能有一个进程在管程内活动,使用condition变量让进入管程而无法继续执行的进程阻塞自己。 例子 先来看一段有问题的代码: #define TRUE 1 #define MAX 100 void insert_item(int); int remove_item(); int count ...

synchronized和ReentrantLock有什么区别呢? - 《java核心技术》笔记

ReentrantLock能够实现很多synchronized无法做到的细节控制,比如公平性fairness,或者利用定义条件等。 知识点扩展: 线程安全 线程安全的定义 保证多线程环境下共享的、可修改的状态的正确性。 进而推导出保证线程安全的两个方法: 封装:将对象内部状态隐藏、保护起来。 不可变。 线程安全需要的几个基本特性 原子性:相关操作不会中途被其他线程干扰,一般通过同步机制实现; 可见性:一个线程修改了某个共享变量,其状态能理解被其他线程知晓。 ...

谈谈你知道的设计模式? - 《java核心技术》笔记

分类 按照模式的应用目标大致分类: 创建型模式:是对对象创建过程的问题和解决方案的总结,比如单例、工厂、构建器、原型。 结构型模式:针对软件设计结构的总结,关注于类、对象继承、组合方式的实践经验,比如适配器、装饰者、桥接、代理、组合、外观、享元。 ...

谈谈接口和抽象类有什么区别? - 《java核心技术》笔记

回答 接口是行为的抽象,是抽象方法的集合,目的是API定义和实现分离。不包含任何非常量成员以及非静态方法;java8后增加了default method,java9后可以定义private defult method。比如java8中的Collection增加了一系列关于Lambda、Stream的default method。 抽象类是不能被实例化的类,主要目的是代码重用。 S.O.L.I.D原则 ...

Java有几种文件拷贝方式?哪一种最高效? - 《java核心技术》笔记

java的几种文件拷贝方式?哪一种最高效? java.io的FileInputStream/FileOutputStream或者java.nio的transferTo/transferFrom。 nio方式可能更快,因为使用了零拷贝技术,数据传输不需要切换到用户态参与,减少了上下文切换和不必要的内存拷贝。 比如应用读取数据时,先在内核态将数据从磁盘读取到内核缓存,再切换到用户态将数据从内核缓存读取到用户缓存。 而NIO transferTo则直接在内核中进行数据拷贝。 提高类似拷贝等IO操作的性能的原则 使用缓存,减少IO次数; 使用transferTo等机制, ...

Java提供了哪些IO方式? NIO如何实现多路复用? - 《java核心技术》笔记

简述 同步阻塞IO库:传统的java.io包下面一些熟知的IO功能,比如File抽象,输入输出流等,交互方式是同步阻塞。java.net下面提供的部分网络API,比如Socket、ServerSocket、HttpURLConnection; 1.4引入的NIO,提供了Channel、Selector、Buffer等新的抽象,可以用于构建多路复用的、同步非阻塞IO,同时提供了更接近OS底层的高性能数据操作方式; ...

如何保证集合是线程安全的? ConcurrentHashMap如何实现高效地线程安全? - 《java核心技术》笔记

简述 问:为什么需要ConcurrentHashMap? 答:因为Hashtable本身比较低效,它在所有的put、get、size方法上面加上了“synchronized”。而Collections提供的同步包装器,只是将“this”作为互斥的mutex。 早期的ConcurrentHashMap基于: 分段锁,将内部进行分段(Segment),里面是HashEntry的数组; HashEntry内部使用volatile的value字段保证可见性,也利用了不可变对象的机制以改进利用Unsafe提供的底层能力, ...

对比Hashtable、HashMap、TreeMap有什么不同? - 《java核心技术》笔记

简单回答: hashtable是同步的,不支持null的键值; HashMap不是同步的,支持null的键值,put和get可以达到常数时间的性能; TreeMap基于红黑树,put、get、remove都是O(log(n)) 注意点:HashMap的性能表现非常依赖于哈希码的有效性,需要注意: equals相等的话,hashCode一定要相等,所以重写了hashCode也要重写equals; hashCode需要保持一致性,状态改变返回的哈希值仍然要一致; ...

对比Vector、ArrayList、LinkedList有何区别 - 《java核心技术》笔记

实现方式不同 Vector是java早期提供的线程安全的动态数组,内部用对象数组来保存数据,可以自动增加容量。 ArrayList是应用更加广泛的动态数组实现,本身不是线程安全。也可以自动扩容,Vector会增加1倍,ArrayList则是50%。 LinkedList是双向链表,不能自动扩容,也是线程不安全的。 Vector和ArrayList作为动态数组,其内部元素是以数组形式顺序存储的,除了头尾插入删除外其他位置性能较差。LinkedList进行节点插入删除则高效,但是随机访问性能比动态数组慢。 可以看到java的集合框架,Collection是所有集合的根,扩展开来三大类: ...

动态代理是基于什么原理 - 《Java核心技术》笔记

动态代理是一种代理机制,通过代理可以让调用者与实现者之间进行解耦,比如进行RPC调用的时候,框架底层的寻址、序列化等。 使用JDK动态代理的简单例子: public class MyDynamicProxy { public static void main (String[] args) { HelloImpl hello = new HelloImpl(); MyInvocationHandler ...

String、StringBuffer、StringBuilder的区别 - 《Java核心技术》笔记

String:典型的immutable类,被声明为final class,所有属性也都是final的。不可变对象的优先是被多线程访问的时候不需要锁和等待的时间。 StringBuffer:是为解决String拼接产生太多中间对象而设计的,可以用append或add把字符串添加到指定位置。它是一个线程安全的可修改字符串,把各种修改数据的方法都加上了synchronize关键字,有性能开销; StringBuilder:非线程安全版本的StringBuffer。 StringBuffer和StringBuilder底层都是使用了可修改数组。 String因为使用过于频繁,java为了避免在一个系统中使用大量的String对象,引入了字符串常量池,当通过直接量给String对象引用赋值的时候,会先检查常量池中是否有值相同的字符串对象, ...

强引用、软引用、弱引用、幻象引用 - 《Java核心技术》笔记

强引用:我们常见的普通对象引用。在强引用中,如果不让该对象指向为空,垃圾回收器绝对不会回收它。除非当出现内存空间不足的时候。jvm抛出oom导致程序异常中止的时候,才会回收具有强引用的对象来解决内存空间不足问题。 Object obj =new Object(); // 强引用 obj = null;//这时候为垃圾回收器回收这个对象,至于什么时候回收,取决于垃圾回收器的算法 软引用:相对强引用弱化一些, ...

final、finally、finalize的区别 - 《Java核心技术》笔记

final可以用来修饰变量、类、方法,final修饰的变量不可修改,final修饰的类不可扩展,final修饰的方法不可重写。 finally是保证重点代码一定要被执行到的机制。 finalize是Object的一个方法,它的设计目的是保证对象在被垃圾收集前完成特定资源的回收,已经不被推荐使用。推荐使用Cleaner机制: public class CleaningExample implements AutoCloseable { // A cleaner, preferably one ...

Exception和Error的区别-《Java核心技术》笔记

Exception是程序正常运行时可以预料到并且应该被捕获的情况,Error是指在正常情况下不太可能出现的情况。绝大部分Error都会导致程序处于非正常、不可恢复的情况,所以不便于也不应该被捕获,比如OutofMemoryError。Exception分为checked和unchecked,checked在代码里必须显式捕获,比如IOException,而unchecked是不可查异常,比如NullPointerException、ArrayIndexOutOfBoundException,通常是可以编码避免的逻辑错误。 抛异常的最佳实践:throw early,catch late。 try-catch会产生额外的性能开销,建议仅捕获有必要的代码段, ...

“解释执行”的理解-《Java核心技术》笔记

编译是将源程序翻译成可执行的目标代码,翻译与执行是分开的。而解释是对源程序的翻译与执行一步到位完成,不生成可存储的目标代码。最大的区别在于控制权:对于解释执行而言,程序运行时的控制权在解释器而不在用户程序;对编译执行而言,程序运行时的控制权在用户。 根据程序执行时的基本表示是实际计算机上的机器语言还是虚拟机的机器语言,可以分为两大类:编译型语言和解释型语言。 由编译型语言编写的源程序需要经过编译、汇编和链接才能生成目标代码,然后机器执行目标代码得出结果。目标代码由机器指令组成,一般不能独立运行; 解释型语言中,翻译器并不生成目标代码,而是产生易于执行的中间代码, ...

int和Integer有什么区别?-《Java核心技术》

自动装箱、拆箱 Integer是int对应的包装类,有一个int类型的字段存储数据,并且提供了基本操作,比如数字运算、int和字符串之间的转换等。java5后引入了自动装箱和拆箱功能。 java5中新增的valueOf可以在调用时使用缓存机制,默认是-128~127,可以通过-XX:AutoBoxCacheMax=N调整缓存机制也存在与Boolean、Short(-128~127)、Byte(全部缓存)、Character( ...

服务化架构的演进

第一阶段:服务拆分与聚合 底层业务进行RPC拆分; 上层聚合业务进行REST拆分; 优点 API接口和rpc业务服务分层 业务按高内聚低耦合的方式拆分 基本实现了业务的服务化 部分业务服务下沉支撑多产品线公用 不足 流量调度能力欠缺 无实际意义耦合,抗风险能力欠缺 监控和治理能力欠缺 业务拆分依然存在不合理耦合 第二阶段:服务划分、网关接入 按业务类型进行更精细服务划分; 适度的聚合业务REST服务拆分引入接入网关; ...

java一些优化点

减少临时对象; 减少list的拷贝,如果要添加到末尾,不要新增一个临时对象; 在初始化map和list的时候,在一开始设置初始化容量,减少扩容引起的数据拷贝; if else如果是string,用switch替换; 删除缓存可能会引起性能提升; 可以按照index寻址的,不要用map。 其实思路跟C++差不多。 ...

C++性能优化的一些tips

存储数据从unordered_map换成vector,vector是连续内存存储,前者获取数据需要大概300ns,后者100ns。怎么解决key的问题:在一个配置文件中填写unordered_map中的key的顺序,按照顺序把数据插入vector; vector使用emplace_back不用pull_back,前者是原地构造。 std::future多线程; 如果每次请求都需要很多同样类型的数据A(比如预估方法中,每次请求都需要抽取一堆feature),那么可以在程序启动的时候提前申请很多(比如一万个) ...

《数据密集型应用系统设计》整理10

第十一章 流处理系统 为了解决批处理需要一定时间后才能处理的问题,流式处理在每秒钟结束时(甚至持续不断)处理每秒的数据,完全放弃固定的时间片,有事件就处理。 “流”是指随着时间的推移而持续可用的数据。 发送事件流 在流处理的上下文中,记录通常被称为事件,但本质上跟批处理是一回事:一个小的、独立的、不可变的对象。 数据产出后的流转阶段,批处理选择通过文件或数据库连接生产者和消费者:生产者将其生产的每个事件写入数据存储, ...