Java并发编程

上传人:桔**** 文档编号:508592754 上传时间:2023-10-07 格式:DOCX 页数:20 大小:1.12MB
返回 下载 相关 举报
Java并发编程_第1页
第1页 / 共20页
Java并发编程_第2页
第2页 / 共20页
Java并发编程_第3页
第3页 / 共20页
Java并发编程_第4页
第4页 / 共20页
Java并发编程_第5页
第5页 / 共20页
点击查看更多>>
资源描述

《Java并发编程》由会员分享,可在线阅读,更多相关《Java并发编程(20页珍藏版)》请在金锄头文库上搜索。

1、Java并发编程快么?这个问题肯定是错的,并发比串行慢的原因在于:线程有创建和上下文切换的开销上下文切换即使是单核处理器也支持多线程执行代码,CPU通过给每个线程分配CPU时间片来实现这个机制。CPU通过时间片分配的算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保持上一个任务的状态,以便下次切换回这个任务时,可以再加之这个任务的状态。所以任务从保存到再加载的过程就是一次上下文切换。如何减少上下文切换无锁并发编程:多线程竞争锁,会引起上下文切换,所以多线程处理数据时,可以用一些办法避免使用锁,如将数据的ID按照Hash算法取模分段,不同的线程处理不同段的数据CA

2、S算法:Java的Atomic包使用CAS算法来更新数据,而不需要加锁。使用最少线程:避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样会造成大量线程处于等待协程:在单行线程中实现多任务调度,并在单线程中维持多个任务的切换避免死锁的几种方式避免一个线程同时获取多个锁避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。对于数据库锁,加锁和解锁必须在一个数据库连接中里,否则会出现解锁失败的情况。资源限制资源限制指的是程序的执行速度受限于计算机硬件资源或软件资源,如服务器的带宽只有2Mb/

3、s,某个资源的下载速度为1Mb/s,系统启动10个线程去下载资源,下载速度不会变成10Mb/s,所以在进行并发的时候回考虑资源的限制。硬件资源限制有带宽的上传/下载速度、硬盘的读写速度和CPU的处理速度。软件资源限制有数据库的连接数和socket连接数等。资源限制引来的问题:为了将代码执行速度加快将代码中串行执行的部分变成并发执行,因为资源受限,仍然在串行执行,这时候程序不仅不会加快,反而会变慢,因为增加了上下文切换和资源调度的时间。如何解决资源限制问题:可以使用集群并行执行程序,既然单机的资源有限,那么可以让程序在多机上运行,比如使用ODPS、Hadoop或者自己搭个服务器集群,不同的机器处

4、理不同的数据,可以通过“数据ID%机器数”,计算得到一个机器编号,然后由对应编号的机器处理这个数据,对于软件资源受限,可以使用资源池来复用如使用连接池将数据库和Socket连接复用,或者在调用对方webservice接口获取数据只建立一个连接。Java并发机制的底层实现原理Java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化为汇编指令在CPU上执行,Java所使用的并发机制依赖于JVM的实现和CPU的指令volatile的应用volatile是轻量级的synchronized,在多处理器并发中保证了共享变量的可见性,可见性是指当一个线程修改了

5、一个共享变量,另一个线程能读到修改的值,它不会引起线程上下文切换和调度volatile在java代码转换为汇编代码 会多了一个Lock前缀的指令,在多核处理器下发生两件事情将当前处理器缓存行的数据写回到系统内存将这个协会内存的操作会使得其他CPU力缓存了该内存的地址的数据无效为了提高处理速度,处理器不直接和内存通信,而是将系统内存的数据读到内部缓存(L1,L2或其他)后再进行操作,但操作完不知道何时回写到内存,如果声明了volatile的变量进行写操作,JVM就会向处理器发送一条Lock前缀的指令,将这个变量所在缓存行的数据写回到系统内存,但是就是写会内存,如果其他处理器缓存的值还是旧的,再执

6、行计算操作就会有问题,所以在多处理器下为了保证各个处理器的缓存是一致,就会执行缓存一致性协议,每个处理器通过嗅探在总线上传播的数据来检查自己的缓存值是否过期,当处理器发现自己缓存行所对应的内存地址被修改,就会将当前处理器缓存行设置为无效,当处理器对数据进行修改操作,会重新从系统内存读到处理器缓存中synchronized的和应用javase1.6 对synchronized进行各种优化,过去被人称为重量级锁。java每个对象都是锁对于普通同步方法,锁就是实例对象对于静态同步方法,锁就是当前类的Class对象对于同步代码块,锁就是Synchonized括号里配置的对象JVM基于进入和退出Moni

7、tor对象来实现方法同步和代码块同步synchronized用的锁是存在Java对象头里的。Java对象头里的Mark Word力默认储存对象的HashCode,分代年龄和锁标记位。在运行期间,MarkWord储存的数据会随着锁标记位的变化而变化Javase1.6中 锁一共有4种状态,级别从低到高为:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级,目的是为了提高获得锁和释放锁的效率偏向锁:大多数情况下,锁不仅不存在多线程竞争,而且总是同一个线程多次获取,为了让线程获得锁的代价更低引入偏向锁。当某一线程访问同步块时,会在对象头和栈帧中的琐

8、记录里存储锁偏向的线程ID,以后该线程在进入该同步块的时候,不需要再次使用CAS原子操作进行加锁和解锁,只需要简单的测试一下对象头中的Mark Word是否存在指向当前线程的偏向锁。如果测试成功,则表示获得锁,否则检测是否设置有偏向锁,如果没有,则使用CAS竞争锁,否则偏向锁指向该线程。轻量级锁:线程执行同步块之前,会在线程私有的栈帧中开辟用于存储锁记录的空间,称为Displaced Mark Word。然后线程尝试将对象Mark Word的替换为指向Displaced Mark Word记录的指针,如果成功,那么当前线程获得锁,如果失败,那么使用自旋获得锁。原子操作的实现原理处理器实现原子操

9、作:使用总线锁保证原子性,使用缓存锁保证原子性(修改内存地址,缓存一致性机制:阻止同时修改由2个以上的处理器缓存的内存区域数据)JAVA实现原子操作:循环使用CAS实现原子操作public class Counter private AtomicInteger atomicI = new AtomicInteger(0); private int i = 0; public static void main(String args) final Counter cas = new Counter(); List ts = new ArrayList(600); long start = Sys

10、tem.currentTimeMillis(); for (int j = 0; j 100; j+) Thread t = new Thread(new Runnable() Override public void run() for (int i = 0; i 10000; i+) cas.count(); cas.safeCount(); ); ts.add(t); for (Thread t : ts) t.start(); / 等待所有线程执行完成 for (Thread t : ts) try t.join(); catch (InterruptedException e) e.

11、printStackTrace(); System.out.println(cas.i); System.out.println(cas.atomicI.get(); System.out.println(System.currentTimeMillis() - start); /* * 使用CAS实现线程安全计数器 */ private void safeCount() for (;) int i = atomicI.get(); boolean suc = atomicI.compareAndSet(i, +i); if (suc) break; /* * 非线程安全计数器 */ priv

12、ate void count() i+; CAS实现原子操作的三大问题ABA问题:因为CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A。循环时间长开销大。自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。如果JVM能支持处理器提供的pause指令那么效率会有一定的提升,pause指令有两个作用,第一它可以延迟流水线执

13、行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零。第二它可以避免在退出循环的时候因内存顺序冲突(memory order violation)而引起CPU流水线被清空(CPU pipeline flush),从而提高CPU的执行效率。只能保证一个共享变量的原子操作。当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁,或者有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。比如有两个共享变量i=2,j=a,合并一下ij=2a,然后用CAS来操作ij。从Java1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行CAS操作。Java内存模型内容较多涉及到内存模型、重排序http:/ class DoubleCheckedlocking private static Instance instance; public static Instance getInstance() if(instance=null) synchronized(DoubleCheckedlocking.class) if(instance=null

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 建筑/环境 > 施工组织

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号