根据我的理解是,web应用好多人同一时间用(多个人就是多线程=》一起用就产生了高并发),如果对同一个数据进行操作,避免出现脏读或者异步产生的后果,要用锁把对象锁起来进行同步操作。
此处就讲讲多线程、高并发、锁上的概念和扩展性问题
概念性问题
根据我的理解是,web应用好多人同一时间用(多个人就是多线程=》一起用就产生了高并发这个场景),如果对同一个数据进行操作,避免出现脏读或者异步产生的后果,要用锁把对象锁起来进行同步操作。
此处就讲讲多线程、高并发、锁上的概念和扩展性问题
1. 多线程
main方法启动时是jvm开了一个线程叫主线程,当主线程要做一些并行的事情时,比如发短信和发邮箱想同时做,就要再开一个线程(两个main方法?不好吧),这是如果开多一个线程就能并行操作。
2. 高并发
如果系统并发量突增,要怎么应对,常见的就是
1、分布式SOA架构迁移
2、集群
3、数据库读写分离、集群
4、缓存、异步通信转为消息队列
3. 锁
当时面试被问到锁,虽然之前有看到,但是记的有点模糊,就答了个乐观锁,还是面试官帮我说了个悲观锁我才想起藏在脑海的知识点,锁的出现是为了实现线程安全,线程安全即是共享的数据在多线程调用下的同步阻塞操作。 根据锁的类型,广义上来说有操作系统的锁,数据库锁,还有java上的锁。 常见的概念锁有乐观锁和悲观锁。
- 乐观锁:我很乐观,先不加锁,等其他线程来用我的对象时,我再加上锁。实现:CAS(Compare and Swap 比较并交换),将原本的数据作为条件去查询。
多线程中,如果共享线程有争用,产生了冲突,再采取补偿措施(常见:不断重试,成功为止)
- 悲观锁:我很悲观,做最坏打算,再还没用时先加锁预约。java例子:sychronized关键字,将对象交予jvm进行锁
数据库中的悲观锁:行锁(修改数据不commit)、表锁(db2修改表结构后会将表锁住)、读锁、写锁
- 死锁:两个线程相互调用两个共享对象,形成死循环。
- 类锁:将sychronized关键字加到 类.class上,new的类都会被阻塞
- 对象锁:锁住this,或不写直接加在方法或代码块,完成对象锁,只有调用同一个对象的方法时才阻塞
4. JUC包常用类
1. ReentrantLock重入锁
2. AtomicInteger原子类
为了保证i++这类操作多线程情况下的安全性,源码中维护了一个volatile修饰的value。
扩展:
-
守护线程:守护线程随着所有非守护线程运转,只有所有非挂了,守护才挂。setDeamon(true)设置为守护线程
-
ThreadLocal:线程内部副本类。用set和get方法来存取值,最常见的ThreadLocal使用场景为 用来解决 数据库连接、Session管理等。原理是维护一个map对象,key是threadLocal实例,value是一个线程特有对象 如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本, 副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。
ThreadLocal 类的常用方法
ThreadLocal() : 创建一个线程本地变量 get() : 返回此线程局部变量的当前线程副本中的值 initialValue() : 返回此线程局部变量的当前线程的"初始值" set(T value) : 将此线程局部变量的当前线程副本中的值设置为value
-
volatile:变量关键字。1、能保证数据的可见性,不能保证修改变量的原子性。(能直接从内存中看到最新的变量)2、禁止指令重排序优化
====未完,待更新==========