拉呱:这是第一篇并发的博客,在后续的并发博文中,我会尽力整理出较全的关于并发的知识点,先却分开两个概念,并发与高并发就是多线程操作相同资源时如何保证数据安全,线程安全以及合理利用资源.和它仅一字只差的是高并发,高并发是指服务能够处理很多请求,比如12306的抢票,处理不好,会降低用户的体验度,甚至是服务器宕机
线程一个理解为进程中的一个子任务
QQ就是一个进程,和好友视频聊天可以理解成一个线程
当然,如果程序确实运行在多核的机器上,那么有可能真的是在同时运行
好处: 可以使我们从单个线程这个层次抽身出来,而多任务和多线程也是使用多处理器系统的最合适的方式
死锁
哲学家问题,当哲学家们都不肯把手里的筷子借给其他人,最后的结果就是全部饿死
饥饿
排队打饭,假设所有人都来这一个窗口排队打饭,打完饭也不走,可能就会导致比较瘦弱的女生吃不上饭而饥饿(反应在线程的优先级问题上)
线程被永久的堵塞在进入同步块的状态
等待的线程永远不会被唤醒
独木桥问题,相互谦让,导致最后谁都过不去
多个线程对同一个实例对象中的实例变量进行并发访问,产生的后果就是脏读(读取到了被更改的数据)--存在非线程安全问题
获取到的对象的实例是经过同步处理的,不会出现脏读的现象--线程安全
说到线程的安全性问题,和重排序和happens-before法则是紧密相关的
多线程速度一定会快吗?
关于性能,是具有多面性的,多线程不一定快,单核的处理器也可以实现多线程,就像烤烧饼,CPU分配给各个线程的时间片很短,但是来回的切换是有成本的但是并发通常是提高运行在单核处理器上的程序的性能,表面上看CPU在多个线程上进行切换很浪费时间,但是阻塞是这个问题变得不同,大多数情况下是因为IO或者进行过一项很复杂的计算,如果没有并发,整个程序都将会停止下来
重排序就是编译器,处理器,在不改变程序执行结果的前提下,重新排序指令的执行顺序,以达到最佳的运行效果
数据依赖指的是,某些指令存在某种先后关系,比如相邻的两行执行都访问通同一个变量,并且其中一个指令执行了写操作,那么,这两行指令就存在数据依赖,换言之,执行的顺序不能改变,否者得出错误的结果
因此,编译器和处理器仅仅对没有数据依赖的指令进行重排序
指令 | 实例 |
---|---|
读后写 | a=b ; b=1; |
写后读 | a=1; b=a; |
写后写 | a=1; a=2; |
在单线程的开发中程序员不需要知道指令是如何进行重排序的,只是简单认为程序是按顺序执行就行,故 意为:貌似是串行的
举个例子,假设多个线程并发访问下面两个方法
boolean flag;
private int a;
public void read(){
a=1;
flag=true;
}
public void write(){
if(flag){
int b = a+1;
System.out.println("b=="+b);
}
}
上面的代码,a=1,flag=ture;显然没有依赖关系,因此可能会被重排序成flag=true; a=1;这时候就会出现问题,当执行到fl,ag=ture,cpu的执行权被另一个线程抢去执行write(),write()里面的输出语句输出的不再是2,而是其他意想不到的值
int a=1; // 1
int b =2; //2
int c =3; //3
在上面代码中 1happens-before 2 3
private ReentrantLock lock = new ReentrantLock();
public void read(){
lock.lock();
//do something ...
lock.unlock(); //1 解锁
}
public void write(){
lock.lock(); // 加锁
//do something ...
lock.unlock();
如上, 1的解锁,后跟着2的加锁
两个操作具有happens-before关系,并不意味着前一个操作一定要在后一个操作之
前执行,(假如两个操作没有数据依赖那么可能会被编译器处理器进行指令的重排序),他只是要求前一个操作的执行结果对后一个操作是可见的(也就是前一个操作不一定先开始,但是它一定要比后一个操作先结束)让其他线程看到结果,前一个操作肯定要把执行的结果,从他自己的缓存中刷回到内存
存在于对象头中
对象头中的信息
Mark Word:存储对象的hashset值,锁信息
Class MetaData Address:存储对象所属类的位置
Array Length : 数组对象特有的标记数组的长度
java中每一个对象都可被当作同步的锁,这些锁就叫做内置锁,例如 Synchronized修饰方法,获取到this对象锁,修饰静态方法,获取到Class类锁,同步代码块里面可以设置this对象锁,非this对象锁等等
前者指该锁一次性只能被一条线程占有,后者表示该锁一次性可以被多条线程占有synchronized和ReentarntLock都是互斥的,而ReentrantReadWriteLock中的读锁,是共享的,读读共享
这三种锁是指锁的状态,并且是针对synchronized,java5通过引入锁的升级来实现高效的synchronized,这三种锁的状态,是通过对象监视器在对象头中的字段来区分
运行流程:
当前线程获取到锁,修改锁对象头里面的Mark Word里面的锁标志位,然后去执行同步代码体,这时候,其他的线程也对象头信息复制到虚拟机栈,企图去更改锁标志位,但是上一个线程没有释放,他就不停的尝试去修改,直到对象锁被释放了为止
可重入锁,有叫递归锁,就是说某一个线程运气比较好,拿到锁之后,在释放之前,再次拿到了这个锁,而且不会被锁阻塞
/*
* 经典的验证 锁的重复问题 ,在单一的线程下, a() 想在 未释放锁 的前提下 调用b(),前提就是可冲入锁
* */
public void a() {
lock.lock();
System.out.println("a");
b();
lock.unlock();
}
public void b() {
lock.lock();
System.out.println("b");
lock.unlock();
}
实例二: synchronized也是一把重入锁
public class safe{
synchronized public void method01(){
....
method02();
}
synchronized public void method02(){
....
}
}
method01() 和 method02 () 都是线程安全的,假如当前线程拿到对象锁后,在执行method01()时,碰到了method(),他可以重复拿到锁,而不会被阻塞!
容易和Synchronized方法,或者代码块的特性混淆:两条线程分别竞争执行method01()和method02() ,无论哪条线程正在执行 Synchronized方法也好,同步代码块也好,另一条线程都不能执行其他任意Synchronized方法或者代码块
其中Synchronized 和 locked 都是可重入锁!
如过多个线程使用多个锁对象,一定是一部执行,锁不住线程!
public class siSuo {
Object a = new Object();
Object b = new Object();
public void method01(){
synchronized (a){
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
synchronized(b){
System.out.println("method1执行了");
}
}
}
public void method02(){
synchronized (b){
synchronized(a){
System.out.println("method2执行了");
}
}
}
public static void main(String[] args) {
siSuo siSuo = new siSuo();
new Thread(()->{
siSuo.method01();
}).start();
new Thread(()->{
siSuo.method02();
}).start();
}
}
Lock锁分为公平锁和非公平锁,所谓公平锁,就是表示线程获取锁的顺序,是按照线程加锁的顺序来实现的,也就是FIFO的顺序先进先出的顺序,而非公平锁描述的则是一种锁的随机抢占机制,还可能会导致一些线程根本抢不着锁而被饿死,结果就是不公平了
就像生活中乐观的人,什么事都往好处想,因此它每次拿到数据之后呢,都认为别人不会来修改它的值,也就是读写不互斥,但是为了安全,他需要在更新数据之前判断一下,有没有人修改过,java.util.Concurrent.atomic包下的原子类,就是乐观锁的实现方法cas完成的
就像生活中悲观的人,什么事都往坏处想,因此它在每次拿数据的时候,都会加上锁阻塞住其他的线程,因为它总是想其他线程肯定回来修改它拿到的数据,传统的关系型数据库中就大量的使用了悲观锁,如行锁,表锁,读锁,写锁等等,Synchronized 和 ReentrantLock都是悲观锁思想的实现
分段式锁是一种设计理念分段锁的设计目的就是细化锁的颗粒度,当操作不需要操作整个数组的时候,仅仅获取它想要的那一段数据的锁就可以,而其他线程仍然可以获取其他段的锁的数据的内容
原文:https://www.cnblogs.com/ZhuChangwu/p/11150268.html