Java基础复习一之多线程(并发,内存模型)

来源:互联网 发布:十字绣制作软件 编辑:程序博客网 时间:2024/05/22 03:21

前言:毕业来北京转眼一年半了,但是没有太多的成绩。没有太多的记录和沉淀。现在开始复习一下基础的知识。涉及到的有多线程,集合,JVM,NIO,数据库,操作系统。后面还是想走实时处理那一块,可能会有那方面的研究。


多线程:为啥用?因为想去执行不同的任务,或利用现状多核的处理器。而因为线程相较于进程轻量级。

线程之间可以共享一个变量和资源,一起访问某个资源,所以有了并发(同步发生)。但为了访问的秩序(线程安全)呢,所以有了同步(线程在资源前排队,需要锁)。为了实现更高级的线程一些功能,多个线程之间交互,所以有了信号量


++++同步:

在java语言中同步很直接的就是:synchronized 同步标志,实际就是取得锁的过程。

synchronized修饰普通方法= synchronized(this){代码块},对象锁,监视器
synchronized修饰静态方法= synchronized(A.class){代码块},类锁
(synchronized修饰Thread的RUN和unable的RUN,一个是普通,一个是静态(其他线程同步)。)

synchronized用到了锁,锁保证了互斥(mutual exclusion) 和可见性(visibility)。每次只能有一个线程持有锁。当前锁修改的共享变了,下个进入锁的线程可以看到。

代码块的范围可以更细一点。

volatile可以用在任何变量前面(final除外)。保证了可见性。

++++线程通讯:
因为有了同步,用了锁,那么呢问题来了,我想退出锁,怎么通知其他人,我要退出了呢,所以有了信号量。JAVA的对象呢,既可以当锁用,又可以当信号量,所以在同步的方法中,通过:this.wait(); / this.notify();  一个等待被唤醒,一个通知其他的线程可以来排队了。

好像synchronized可以解决所有同步加锁的问题了,但是,默认用对象的锁,毕竟只有一个,如果我认为一个JAVA对象对应N(N>1)个锁怎么办呢?其实用最原生的锁对象不就OK了?,之前的信号量,也可以通过锁对象来构造(同理可以多个) --这段理解有误,synchronized、volatile只是关键字,而LOCK是对象,更高级一点,提供了更高级的功能。try获取锁、 公平锁等。还可以通过不同的条件,来让不同线程,等待不同的条件。
    final Lock lock = new ReentrantLock();    final Condition notFull  = lock.newCondition();     final Condition notEmpty = lock.newCondition();
这里稍微不同:lock.lock() /unlock() 注意用 finally 。notFull.await()/notFull.notify()

说到信号量再讲讲线程间通信的另一种:管道。管道相连。一个读,一个写。堵塞队列也可以实现。


++++线程控制:
JAVA并发包里有一些并发控制的类。这个是高级于:synchronized,volatile(低级) LOCK(中级)的
CountDownLatch 门插销计数器:对一个线程用此对象等待方法,其他线程,对象countDown()每次减一;减到0唤起await的线程。
CycliBarrier. 等所有线程都达到一个起跑线后才能开始继续运行。

+++++并发集合

JAVA原生的集合都是fast-fail的,为了在多线程下,同步的使用集合有了一些集成好的并发集合。

ConcurrentHashMap:锁分离技术,在HASH之前有SEGMENT层,每个段上加锁。


++++非阻塞方式合集
volatile关键字时非阻塞的,但是对同步支持不完全。所以JAVA自己实现了一下常用的非阻塞的线程安全的变量,都是利用了硬件的CAS特性来完成,可以说利用硬件保证了原子性。(锁都是阻塞的,将读-改-存 原子操作化)
AtomicBoolean、AtomicInteger、AtomicReference
提供对数组类型的变量进行处理的Java类,AtomicIntegerArray、AtomicLongArray和AtomicReferenceArray类。(同上,只是放在类数组里,调用时也只是多了一个操作元素索引的参数)


++++以上都是可以使用对象,锁来控制多线程并发访问。后面讲讲内存模型和一些关键字:final,volatile.
抽象的讲,多个线程间有共享 的内存,也有自己的本地内存(抽象出CPU缓存寄存器缓存等的地方)-(考虑可见性)-。JAVA一条语句可能会被拆分成多条指令(考虑非原子性),指令之间也可能会被调优导致重新排序(重排序)。
final 指的是不可变的,只能初始化一次,这样的话,在多线程中就不会有线程安全的问题。



参考:
http://blog.csdn.net/escaflone/article/details/10418651
http://www.ibm.com/developerworks/cn/java/j-jtp06197.html
http://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example

0 0
原创粉丝点击