由于不想错过秋招,并且为明年春招做准备,之后会不定期的在这里整理一些问题。
语言——java、python、cpp、scala
并发编程、java内存模型(Java Memory Model):
线程之间的通信机制有两种:
共享内存 :不同线程共享内存中的公共状态来隐式的通行,比较典型的就是通过共享对象来进行通信。对于线程的同步必须是显式的,即程序员手动指定某个方法或者某段代码必须在线程之间互斥的进行。
消息传递:线程之间没有公共状态,线程之间必须通过明确的发送信息进行显式通信,比较典型的就是调用wait()或者notify()等函数的方式。同步是隐式的,因为消息的发送必须在消息接受前。
内存模型:
每个线程都有自己的本地内存,然后也有主内存。本地内存中有一份共享变量的副本。线程A刷新了自己本地内存中的变量x,但AB需要通信时,会先通过副本刷新主内存中的x,然后线程B再读取主内存中的x,此时B的本地内存中x也成了新值。
内存模型的实现
所有的原始类型变量都在stack中,一个线程中的本地变量对另一个线程是不可见的。而java创建的对象,以及原始类型的封装类则存在heap中(不管是成员变量还是方法中的本地变量)。heap中的变量是可以被共享的,只要另一个线程获得了这个对象,那它就可以访问这个对象的成员变量。
Volatile和sychronized区别
首先要理解线程安全的两个方面:
- 执行控制:目的是控制代码执行顺序及是否可以并发进行
- 内存可见:线程执行的结果在内存中的可见性
特征:
synchronized:是解决执行控制的问题,即阻止其他线程获得当前对象的监控锁,使得被synchronized保护的代码块无法被其他线程所访问,也就无法并发执行。
volatile:解决的是内存可见性的问题。使得所有对volatile变量对读写都直接刷新到主存,即保证了变量的可见性,但只能保证对原始类型变量(除了double、long)的操作原子性。
区别:
- volatile本质是告诉jvm这个变量值是不确定的,需要从主内存中取,而synchronized则是直接锁定当前变量。
- volatile只能针对变量,而synchronized可以用在变量、方法或类的级别。
- volatile只能实现对变量修改的可见性,而无法保证原子性。synchronized则可以保证原子性
- volatile不会造成线程阻塞,而synchronized会造成
- volatile标记变量不会被编译器优化,而synchronized则会被优化。
happen-before原则:
一个线程内,按照代码执行顺序,书写在前面的操作先行发生于书写在后面的操作。
内存栅栏:
为了提高性能,cpu通常不按照顺序执行指令,而是通过重排指令来提高存储器的利用率,但这也意味着会有不可预测的问题发生。内存栅栏就是解决指令重排问题的方法,具体来说,是指处理器在重排时,不能采用先执行栅栏后的内存访问,在执行栅栏前内存访问的方式。这也是volatile的实现方式。
GC回收机制:
类加载机制:
其他:
大数据相关
mysql数据库
mysql主键和唯一索引
之前不太了解唯一索引,这次才知道。唯一索引就是mysql里的unique,可以在创建表时或者建表后增加,如建表后可以用:
1 | CREATE UNIQUE INDEX nm on PERSON(name); |
执行成功后,如果在原表已经有一条类似 (‘1’,’max’,’1995-12-12’)类似的记录后,还要插入如下:
1 | INSERT INTO person(name,birthday) values ('max','1995-12-13'); |
会直接报错,告诉用户name是唯一索引,无法再插入相同。这个有个使用场景,即在高并发下为了保证某一个键不会插入重复信息,需要给这个键增加唯一索引。
主键和唯一索引的区别:
- 唯一索引允许空值,但主键不能为空
- 主键创建后一定包含一个唯一索引,但唯一索引不一定是主键
- 主键可以被其他表引为外间,但唯一索引不能
- 一个表只能有一个主键,但可以有多个外键
mysql里key其实包含三种:PRI(主键),UNQ(唯一索引),MUL(普通key,可以重复)
外键:
一个表的主键可以作为它从表的一个外键,外键本质是一种约束。外键要求和主键Type完全相同(int(10)和int(11)的差别都不可以),用如下语句可以创建外键约束:
1 | alter table my_profile add CONSTRAINT id foreign key(id) references person(id) on delete cascade on update no action; |
注意后面可以对这个键的delete、update进行约定,确定是否进行级联操作。
注意:外键只有InnoDB支持,而MyISAM不支持。
InnoDB和MyISAM的几点区别:
- InnoDB支持事物和外键,而MyISAM不支持
- InnoDB支持行及锁,MyISAM只支持表级锁
- InnoDB不支持全文索引,而MyISAM支持
- MyISAM相对简单,提供了告诉存储和检索,在效率上要优于InnoDB,适合管理非事物表,适合有大量的select的程序。
- InnoDB则更安全,多用户的并发性能更好,适合有大量insert、update的事物处理的应用程序。
MySQL的锁机制:
mysql有几种类型的锁:
- 排他锁(写锁,X锁):如果事务T对A加上排他锁,那其他事务不能对A加任何类型的锁。获得排他锁既能读数据也能写数据。
- 共享锁(读锁,S锁):如果事务T对A加上共享锁,则其他事务不能对A加排他锁,获得共享锁的事务只能读数据,不能写数据。
- 行级锁:行级锁氛围共享锁和排他锁,行级锁是mysql中锁定粒度最细的锁。行级锁开销大,加锁慢,锁定力度小,发生锁冲突的概率最低,并发度最高。
- 表级锁:表级锁分为表共享锁和表独占锁。表级锁开销小,加锁快,锁定粒度大,发生冲突概率高,并发度低。
- 悲观锁:即悲观并发控制,简称PCC。悲观锁是指在数据处理过程中加锁,使数据处于锁定状态,使用数据库锁机制实现。注意在mysql中使用悲观锁要关闭mysql的自动提交。——安全,但产生额外开销,增加产生死锁机会。
- 乐观锁:通过记录数据版本的方式实现。为数据增加一个版本标识,读取数据时,将版本标识一起取出,数据每更新一次,就对版本标识进行更新。
语句示例:
1 | #共享锁 |
实现:
InnoDB实现行级锁需要在表上增加索引,InnoDB会对索引项加锁,即当InnoDB没有索引项时,也只能进行表锁。
InnoDB中MVCC的一些理解
mvcc(multiversion concurrency control),即多版本并发控制技术,它使得行锁不再简单通过锁来进行并发控制。它本身希望同一个数据有多个版本,版本号是单向增长的。而读事务只读在该事务开始前的数据库的快照。实质是用来解决读写冲突的无锁并发控制。乐观锁就是这种思路。