java并发系列一(java内存模型)

作为一个半路出家学java的菜菜菜鸟,真的是感觉路漫漫其修远兮,工作间隙看了大约两周的java并发,现在开始慢慢总结。

1.线程间的通信

线程之间的协作主要有几个点,wait,notify,notiyALl(),显示Condition对象,队列中的生产者消费者等等。主要就是条件队列的使用。我将结合java编程思想和java并发编程这两本书中的内容进行整理。
1,条件队列
首先引入一个概念:条件谓词(我了个擦,感觉跟上学的时候学英语一样, 还谓词),通俗的说就是使某个操作称为状态依赖的前提条件。
条件等待中存在一种重要的三元关系,包括加锁,等待(即wait方法),和一个条件谓词。条件谓词中包含多个状态变量,而状态变量由一个锁来保护。因此在测试条件谓词前必须先持有这个对象!!!!!(重点!!!)。锁对象与条件队列对象必须是同一个对象。这里有一点需要注意哈,wait/notify/notifyAll方法都是Object的方法。
wait方法释放锁,阻塞当前线程,并等待直到超时,然后线程被中断或者通过一个通知被唤醒。
2,丢失的信号
丢失的信号(不太好理解,要多读几遍):线程必须等待一个已经为真的条件,但在开始等待之前没有检查条件谓词。
上代码

T1
synchronized(lock){
    condition = false;
    lock.notify();
}

T2
while(condition){
//point1
  synchronized(lock){
  lock.wait();
  }
}

T1为唤醒线程,T2为等待线程。当T2执行到point1的时候线程切换到T1.T1执行完毕,条件已经改变。T2这时候盲目的进入wait(),然后开始无限的等待。这个时候就会产生死锁。解决办法就是T2先获取锁,然后再对条件谓词进行判断。

2,显示的Condition对象
//惭愧,这个知识点,我还没理解透。没太明白
lock.newCondition创建一个Condition.Condition比内置条件提供了更加丰富的功能。注意,Condition对象中,与wait,notify,notifyAll方法分别对应的是await,signal,signalAll.(!!!切记!!!!)一定要确保使用正确的版本await和signal!!!

3,队列中的生产者,消费者
这个主要是讲一下队列BlockingQueue,它大大简化了生产者-消费者的实现过程。最常见的生产者消费者模式就是将线程池与队列结合。
注意:在构建高可靠的应用程序时,有界队列是一种强大的资源管理工具,它能抑制并防止产生过多的工作项。使应用程序在负荷过重的情况下变得更加强壮。
常用的队列如linkedBlockingQueue(无界队列),ArrayBlockingQueue(有界队列)二者分别与linkedList和ArrayList相似。

2,重排序

//重排序这部分我真的是看的很浅,只能是浅显的理解一下,以后再深入的慢慢了解吧
我们总是会觉得程序编译的顺序与编写的顺序是相同的。但是呢,我擦勒,编译器中生成的指令顺序是可以与源代码不同的。为了提高性能,编译器和处理器会对指令进行重排序。重排序会经过如下图的3个步骤:
1,编译器优化重排序2,指令级别并行重排序3,内存系统重排序
在这里插入图片描述
那么java内存模型的概念又出来了,简称JMM,是语言级别的内存模型。主要是用于控制共享变量的写入何时对其他线程可见。
其中,处理器不会对存在数据依赖性的 指令进行重排序。所谓数据依赖性,比如i++,

as-if-serial
简单来说,单线程 程序的执行结果不会被改变
happens-before
如果一个操作执行的结果要对另一个操作可见,那么这两个操作之间必须满足happens-before原则。它是为了保证正确同步的多线程程序的执行结果不会被改变。
具体规则如下:
程序顺序规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作。
监视器锁规则:对一个锁的解锁,happens-before于随后对这个锁的加锁。
volatile变量规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读。
传递性:如果A happens-before B,且B happens-before C,那么A happens-before C。
start()规则:如果线程A执行操作ThreadB.start()(启动线程B),那么A线程的ThreadB.start()操作happens-before于线程B中的任意操作。
join()规则:如果线程A执行操作ThreadB.join()并成功返回,那么线程B中的任意操作happens-before于线程A从ThreadB.join()操作成功返回。

顺序一致性(未理解)
1,一个线程中的所有操作必须按照程序的顺序来执行。
2,(不管程序是否同步)所有线程都只能看到一个单一的操作执行顺序。在顺序一致性内存模型中,每个操作都必须原子执行且立刻对所有线程可见。

猜你喜欢

转载自blog.csdn.net/lc138544/article/details/84349871