MySQL锁
MySQL锁表级锁和行级锁MyISAM (MySQL5.5版本以前默认的存储引擎) 仅仅支持表级锁,一锁就锁整张表,这在并发写的情况下性非常差。
InnoDB (MySQL5.5版本后默认的存储引擎) 不光支持表级锁,还支持行级锁,默认为行级锁。行级锁的粒度更小,仅对相关的记录上锁即可(对一行或者多行记录加锁),所以对于并发写入操作来说, InnoDB 的性能更高。
表级锁和行级锁对比:
表级锁: MySQL 中锁定粒度最大的一种锁(全局锁除外),是针对非索引字段加的锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。不过,触发锁冲突的概率最高,高并发下效率极低。表级锁和存储引擎无关,MyISAM 和 InnoDB 引擎都支持表级锁。
行级锁: MySQL 中锁的粒度最小的一种锁,是 针对索引字段加的锁 ,只针对当前操作的行记录进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。行级锁和存储引擎有关,是在存储引擎层面实现的。
InnoDB 的行锁是针对索引字段加的锁,表级锁是针对非索引字段加的 ...
MySQL事务
MySQL事务什么是事务事务是逻辑上的一组操作,要么都执行,要么都不执行。
事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红转账 1000 元,这个转账会涉及到两个关键操作,这两个操作必须都成功或者都失败。
将小明的余额减少 1000 元
将小红的余额增加 1000 元
事务会把这两个操作看成逻辑上的一个整体,这个整体包含的操作要么都成功,要么都要失败。这样就不会出现小明余额减少而小红的余额却并没有增加的情况。
数据库事务大多数情况下,我们在谈论事务的时候,如果没有特指分布式事务,往往指的就是数据库事务。
数据库事务在我们日常开发中接触的最多了。如果你的项目属于单体架构的话,你接触到的往往就是数据库事务了。那数据库事务有什么作用呢?
简单来说,数据库事务可以保证多个对数据库的操作(也就是 SQL 语句)构成一个逻辑上的整体。构成这个逻辑上的整体的这些数据库操作遵循:要么全部执行成功,要么全部不执行 。
事务的 ACID 特性ACID,是指关系型数据库事务正确执行的四个基本要素的缩写。包含:
原子性(Atomicity)
一致性(Consistency)
隔离性(Iso ...
类加载机制
类加载机制现在,我们已经了解了字节码文件的结构,以及JVM如何对内存进行管理,现在只剩下最后一个谜团等待解开了,也就是我们的类字节码文件到底是如何加载到内存中的,加载之后又会做什么事情。
类加载过程首先,要加载一个类,一定是出于某种目的的,比如我们要运行我们的Java程序,那么就必须要加载主类才能运行主类中的主方法,又或是我们需要加载数据库驱动,那么可以通过反射来将对应的数据库驱动类进行加载。
所以,一般在这些情况下,如果类没有被加载,那么会被自动加载:
使用new关键字创建对象时
使用某个类的静态成员(包括方法和字段)的时候(当然,final类型的静态字段有可能在编译的时候被放到了当前类的常量池中,这种情况下是不会触发自动加载的)
使用反射对类信息进行获取的时候(之前的数据库驱动就是这样的)
加载一个类的子类时
加载接口的实现类,且接口带有default的方法默认实现时
比如这种情况,那么需要用到另一个类中的成员字段,所以就必须将另一个类加载之后才能访问:
12345678910111213public class Main { public static voi ...
类文件结构
类文件结构在我们学习C语言的时候,我们的编程过程会经历如下几个阶段:写代码、保存、编译、运行。实际上,最关键的一步是编译,因为只有经历了编译之后,我们所编写的代码才能够翻译为机器可以直接运行的二进制代码,并且在不同的操作系统下,我们的代码都需要进行一次编译之后才能运行。
如果全世界所有的计算机指令集只有x86一种,操作系统只有Windows一种,那也许就不会有Java语言的出现。
随着时代的发展,人们迫切希望能够在不同的操作系统、不同的计算机架构中运行同一套编译之后的代码。本地代码不应该是我们编程的唯一选择,所以,越来越多的语言选择了与操作系统和机器指令集无关的中立格式作为编译后的存储格式。
“一次编写,到处运行”,Java最引以为傲的口号,标志着平台不再是限制编程语言的阻碍。
实际上,Java正式利用了这样的解决方案,将源代码编译为平台无关的中间格式,并通过对应的Java虚拟机读取和运行这些中间格式的编译文件,这样,我们只需要考虑不同平台的虚拟机如何编写,而Java语言本身很轻松地实现了跨平台。
现在,越来越多的开发语言都支持将源代码编译为.class字节码文件格式,以便能够直接 ...
JVM垃圾回收机制
垃圾回收机制我们前面提到,Java会自动管理和释放内存,它不像C/C++那样要求我们手动管理内存,JVM提供了一套全自动的内存管理机制,当一个Java对象不再用到时,JVM会自动将其进行回收并释放内存,那么对象所占内存在什么时候被回收,如何判定对象可以被回收,以及如何去进行回收工作也是JVM需要关注的问题。
对象存活判定算法首先我们来套讨论第一个问题,也就是:对象在什么情况下可以被判定为不再使用已经可以回收了?这里就需要提到以下几种垃圾回收算法了。
引用计数法我们知道,如果我们要经常操作一个对象,那么首先一定会创建一个引用变量:
1234//str就是一个引用类型的变量,它持有对后面字符串对象的引用,可以代表后面这个字符串对象本身String str = "lbwnb";//str.xxxxx...
实际上,我们会发现,只要一个对象还有使用价值,我们就会通过它的引用变量来进行操作,那么可否这样判断一个对象是否还需要被使用:
每个对象都包含一个 引用计数器,用于存放引用计数(其实就是存放被引用的次数)
每当有一个地方引用此对象时,引用计数+1
当引用失效( 比如离 ...
JVM内存区域
JVM内存区域在传统的C/C++开发中,我们经常通过使用申请内存的方式来创建对象或是存放某些数据,但是这样也带来了一些额外的问题,我们要在何时释放这些内存,怎么才能使得内存的使用最高效,因此,内存管理是一个非常严肃的问题。
比如我们就可以通过C语言malloc函数动态申请内存,并用于存放数据,而在Java中,这种操作实际上是不允许的,Java只支持直接使用基本数据类型和对象类型,至于内存到底如何分配,并不是由我们来处理,而是JVM帮助我们进行控制,这样就帮助我们节省很多内存上的工作,虽然带来了很大的便利,但是,一旦出现内存问题,我们就无法像C/C++那样对所管理的内存进行合理地处理,因为所有的内存操作都是由JVM在进行,只有了解了JVM的内存管理机制,我们才能够在出现内存相关问题时找到解决方案。
内存区域划分既然要管理内存,那么肯定不会是杂乱无章的,JVM对内存的管理采用的是分区治理,不同的内存区域有着各自的职责所在,在虚拟机运行时,内存区域如下划分:
我们可以看到,内存区域一共分为5个区域,其中方法区,堆和直接内存是所有线程共享的区域,随着虚拟机的创建而创建,虚拟机的结束而销毁,而 ...