【3】Java并发编程:多线程基本概念

来源:互联网 发布:爱逛街淘宝网首页 编辑:程序博客网 时间:2024/06/05 20:48

Java并发编程一直是开发学习中的重点和难点,难在于许多的基本概念不是短时间内就容易理解。下面就Java并发编程中的涉及多线程的基本概念做一个总结:

1、TPS(Transactions Per Second,每秒事务处理数)

   : 一秒内服务端平均能响应的请求总数

2、高速缓存Cache
3、Java内存模型(Java Memory Model):变量、工作内存、主内存
4、Java内存模型:内存间交互操作

lock(锁定):作用于主内存的变量,它把一个变量标识为一条线程独占的状态。unlock(解锁):作用于主内存变量,它把一个处于锁定状态的变量释放出来,释放后的变量才能被其他线程锁定。read(读取):作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用。load(载入):作用于工作内存变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。use(使用):作用于工作内存变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作。assign(赋值):作用于工作内存变量,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。store(存储):作用于工作内存变量,它把工作内存中的一个变量的值传送到主内存中,以便随后的write操作使用。write(写入):作用于主内存变量,它把store操作从工作内存中得到的变量中的值放入主内存的变量中。

执行时满足以下原则:

不允许read和load、store和write操作之一单独出现,即不允许一个变量从主内存读取了单工作内存不接受,或者从工作内存发起回写了但主内存不接受的情况出现,不允许一个线程丢弃它的最新的assign操作,即变量在工作内存中改变了之后必须该变化同步回主内存。不允许一个线程无原因的(没有发生过任何assign操作)把数据从线程的工作内存同步回主内存。一个新的变量只能在主内存中“诞生”,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量;换句话说,就是对一个变量实施use、store操作之前,必须先执行过了assign和load操作。一个变量在同一个时刻只允许一条线程对其进行lock操作,但lock操作可以被同一条线程重复执行多次,多次执行lock操作后,只有执行相同次数的unlock操作,变量才会被解锁。如果对一个变量执行lock操作,那将会情况工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作初始化变量的值。如果一个变量事先没有被lock操作锁定,那就不允许对它执行unlock操作,也不允许去unlock一个被其它线程锁定住的变量。对一个变量执行unlock之前,必须先把次变量同步回主内存中。

5、long与double的非原子性协定: 允许虚拟机对没有被volatile修饰的64位数据的读写操作划分为2此32位的操作来进行,即允许虚拟机实现选择可以不保证64位数据类型的load、store、read和write这4个操作的原子性。

6、线程的原子性、可见性、有序性
原子性:由JAVA的内存模型来直接保证的原子性变量操作包括read、load、assign、use、store、write。基本数据类型的访问读写是都具有原子性的。如果需要一个更大范围的原子性保证,则可以用同步代码块synchronized关键字。

可见性:指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。volatile、final、synchronized等三个关键字能实现可行性。

有序性(须理解指令重排序):java的天然有序性是如果再本线程内观察,所有的操作都是有有序的;如果再一个线程中观察另一个线程,所有的操作都是无序的。volatile、synchronized两个关键字可保证线程之间操作的有序性。

7、先行发生原则:Java内存模型中定义的两项操作之间的偏序关系。java内存模型定义了一些先行规则,如两个操作之间的关系不在此列,则它们之间就没有顺序性的保障,虚拟机可以随意对它们进行重排序。

程序次序规则:在一个线程内,按照程序代码顺序,书写在前面的操作先行发生于书写在后面的操作。准确的说,应该是控制流顺序而不是程序代码的顺序,因为要考虑循环分之的结构。

管程锁定规则:一个unlock操作线程发生于后面对同一个锁的lock操作。这里必须强调的是同一个锁,而“后面”是指时间上的先后顺序。

volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个变量的读操作。

线程启动规则:thread对象的start()方法先行发生于此线程的每一个动作。

线程终止规则:线程中的所有操作都先行发生于对此线程的终止监测我们可以通过thread.join()方法结束、Thread.isActive()的返回值等手段监测到线程已终止执行。

线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码监测到中断事件的发生,可以通过Thread.interrupted()方法监测到是否有中断发生。

对象终结规则:一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始。

传递性:如果操作A线程发生于操作B,操作B线程发生操作C,那就可以得出操作A线程发生于操作C的结论。

8、java线程:是基于操作系统原生线程模型来实现的。线程模型有:使用内核线程实现、使用用户线程实现、使用用户线程加轻量级进程混合实现。

9、java线程调度:使用的是抢占式线程调度,与抢占式任务调度对应的是协同式任务调度(如一个线程出错,则可能对整个系统崩溃)。

协同式任务调度:线程的执行时间由线程本身控制,线程把自己的工作执行完成之后,要主动通知系统切换到另外一个线程上。

抢占式任务调度:每个线程将由系统来分配执行时间,线程的切换不由线程本身决定。在java中可以设置线程的优先级,优先级越高的则容易被系统选择执行。

10、线程状态

这里写图片描述

11、JAVA线程安全可分为:不可变(final修饰的基本类型,对象则描述为任何行为对不会对其状态产生影响,如String)、绝对线程安全、相对线程安全、线程兼容、线程对立。

12、线程安全方法

互斥同步:又称悲观锁。同步是指在多个线程并发访问共享数据时,保证共享数据在同一个时刻只被一个线程使用。而互斥是实现同步的一种手段,临界区、互斥量、信号量都是主要的互斥实现方式。

synchronized关键字

java.until.concurrent下的ReentrantLock来实现同步,其实现了一些高级功能:

等待可中断:当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情,可中断特性对于处理执行时间非常长的同步快很有帮助。

可实现公平锁:多个线程在等待同一个锁时,必须按照申请锁的时间顺序依次获得锁。而不公平锁则保证这一点,synchronized中的锁时非公平的,ReentrantLock默认也是非公平的,但可以通过构造函数的布尔值来要求使用公平锁。

锁可以绑定多个条件:一个ReentrantLock对象可以同时绑定多个Condition对象,而synchronized中,锁对象的wait()、notify()、notifyAll()方法可以实现一个隐含的条件,如有多个条件则需要额外的田间synchronized。

在jdk6以前的版本中,可用ReentrantLock对象,其性能较好。但在jdk6及以后的版本中对synchronized做了相关优化,性能相差不多,建议在高版本中使用synchronized对象。

非阻塞同步:基于冲突监测的乐观并发策略,就是先进行操作,如果没有其他线程争用共享数据,那操作就成功了;如果共享数据有争用,产生了冲突,那就采取其他补偿措施。可以参考sun.misc.Unsafe;在java.until.concurrent下有一些类实现了此Unsafe机制。如AtomicInteger。

无同步方案:如果不涉及到数据共享,则无须任何同步措施保证正确性。

可重入代码:可以在代码执行的任意时刻中断它,转而去执行另外一段代码,而在控制权返回后,原来的程序不会出现任何的错误。

线程本地存储:如果一段代码中所需要的数据必须与其它代码共享,那就看看这些共享数据的代码是否能保证在同一线程中执行?如果能保证,我们就可以把共享数据的可见范围限制在同一个线程之类,这样无须同步也能保证线程之间不出现数据争用的问题。需要对ThreadLocal对象进行理解。

参考致谢:
1 http://my.oschina.net/aiyungui/blog/488651

0 0
原创粉丝点击