java并发编程实践学习笔记

标签: java 并发 编程 | 发表时间:2015-08-04 15:54 | 作者:
出处:http://m635674608.iteye.com
关键字:
    原子操作:原子为不可再分操作。
   Violation :可见关键字。
   Synchronized:内部隐示锁 
   ReentrantLock:显示锁 
   ReentrantReadWriteLock:读写锁 
   final:创建后不变
 
jmm(java内存模型):
    

 
线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递 均需要通过主存完成
 
线程 thread,runable常用方法
    Interrupt():中断该线程,只是java语法上说要中断,具体实现需要业务上判断, 
    interrupted():判断是否中断,并且清除中断状态。 
    isInterrupted() :判断是否中断,不清除中断状态。 
    join() :等待该线程终止。 
    yield() :暂停执行当前线程,让出资源,让那个jvm的线程排程器 从可执行状态的线程中重新进行排程。也许该线程立马就又可以运行。 
    线程状态:new-》可运行-》排程器调度到运行-》等待,阻塞,睡眠-》运行完毕 
中断:
    如 sock 通讯, read , write 被阻塞,不好中断,可通过关闭 sock.close() 实现中断 ;
 
并发可见关键字:violation
      当多线程修改同一个数据时候,由于jmm限制,并不能立马让other thread察觉。
     硬件上实现:cpu硬件厂商提供了,各个cpu核心数据同步的关卡或栅栏。Java提供了这样的关键字机制:violation
会主动同步各个工作内存的数据到主内存中.
     volatile字段的写操作happen-before后续的对同一个字段的读操作 :详见组后的happen-before规则。
     如 系统线程:
//表示是否运行
private volatile boolean running = false;
64位的 long,double 读写分为2个32位的操作,声明为violation,jmm会规定为原子操作。是否会在64bit机器有限制
 
并发内部隐示锁:synchronized
特性:可见性:和 violation 一样,
      原子性:把一些不是原子操作组合成原子操作。
      当一个 final 变量时候不需要做同步 , 但是一个对像需要内部的成员变量是否 final 。
     当一个变量创建后要变化,需要在修改和获取时候都要加锁。不然遍历时可能 抛出 ConcurrentModificationException 被变化异常。
锁的持有者,谁是锁
    public class Lock (      
       public synchronized  void fun1(){
              //业务运算.       
       };
       public static synchronized void fun2(){
              //业务运算.      
       }
}
Lock a = new Lock();
fun1:锁是 Lock 对象也就是 a this,持有锁这调用的线程。
fun2:锁是 Lock.class,持有锁这调用的线程。
当线程持有了锁,当要进入需要相同锁的地方,可以进入。
 
synchronized 注意地方,缺点:
注意地方:
    锁是用在多线程并发操作:当线程获取到了锁,调用了sleeep(休眠),线程不会释放资源,释放锁,
wait,线程会释放锁,当再次醒来后又要重新获取锁,需要在同步块。
notify:唤醒由于该条件等待的线程中的一个线程,需要在同步块。
notifyAll:唤醒所有。 一般就调用notifyAll:不然可能会造成某些线程假死,点背一直没有唤醒过他。需要在同步块。
缺点:
      当并发时候需要超时中断,不能实现。只能傻等到得到锁业务计算完毕退出。
显示锁:ReentrantLock:
   语义上还有和 synchronized 完全相同,只是更多的功能
写法:
  lock.lock();// 获取锁
  lock.unlock();// 释放锁,一定要和数据库连接一样,放到 finally 中
由于和数据库连接一样,增加了危险性。
常用 api 解释:
     tryLock(long timeout, TimeUnit unit ) // 获取锁,不能返回 false 或一个时间后 不能获取返回。

ReentrantLock的wait,notify, notifyAll:
    和synchronized 的wait,notify,notifyAll对应。
如果使用了ReentrantLock不能使用wait,notify,notifyAll方法。 
//生产者消费者的生产环境,有限的数组,当数组满了后需要等待,消费者清除了数据后需要唤醒生产者线程。 
ReentrantLock lock = new ReentrantLock();
Condition full = lock.newCondition(); 
public void put(String str){
if(isFull()){//是否已经满了
     full.await();
          }

public void get(){
      //清除业务 
      full.notifyAll();

觉得更加有针对性的面向对象的编程。 
 
数据库的类似问题:
    脏读:第一个事物读取第二事物正在更新的数据,如果更新语句尚未完成,则第一个事物读取到的只是一个过程中的数据,而并非真实的结果。oracle的事物默认是:read committed(提交读), 不会出现该问题
   排他锁 :当变更数据,获取排他锁。
   共享锁:查询获取共享锁,数据可以被多线程获取多个共享锁。获取了共享锁,再获取排他锁,需要等待共享锁结束。
 
Java解决数据库的类似问题
   脏读:violation 关键字,可见性 如64bit的long,double。
   排他锁 :默认synchronized,ReentrantLock都是排他锁。
   共享锁:实现类ReentrantReadWriteLock ,读写锁。场景:如我们的系统缓存常量数据一般都是读,很少的修改。



并发类介绍-----原子基本变量
   Boolean:AtomicBoolean 
   Long:AtomicLong 
   引用:AtomicReference 
   链表中的大量数据需要包装,使用域的更新,AtomicReferenceFieldUpdater 
案例:系统的访问次数,你肯定用一个long sum = 0;
sum++方法,
从计算机的原子操作看是有3步 1.取出sum=0 2.加1 sum+1  3.把加的值放回到sum的区域 sum=1;
并发操作要讲究原子操作,我们一般使用 隐藏锁(synchronized)或显示锁(lock).

并发类介绍---CAS(compare and  swap)
  伪代码:
addOne(){
   for(;;){
     int old = 当前的值;
     int new = old+1;
     if(cas(old,new)){
       return;
      }
    }
}
/**
*这一块是cpu指令实现原子,当替换成功返回true,否则false.
*/
cas(int old,int new){
   if(old==当前的值){//就是刚才的当前值,相同表示没有变化。
      当前的值=new;
      return true;
   }else{//如果不相同表示已经被修改,那么就返回false,上面函数再调用cas.. 
      return false
   }
}

并发类介绍-----CAS与锁实现比较
    锁的基本实现:A 线程获取锁,B获取锁等待,B释放锁唤醒所有等待线程,B获取锁
    休眠等待需要操作系统的上下文切换,从用户态到系统态的切换,比较慢。
    如果用cas的话,直接是jvm计算,当超级大并发,竞争异常激烈时候,cas就不一定比锁性能更好了,从这些业务算法上看,计算机的科学也是为了解决具体的事情,那些牛人想破脑袋想出来的。
 
并发类介绍-----缓存队列
   数组(array)如:ArrayList  
   数组链相结合产物:HashMap;
   为了并发操作更快速,使用更加简便设计。并发包java.util.concurrent 
   有限数组(array):ArrayBlockingQueue,
   并发数组链map:ConcurrentHashMap。
   当map很大时候,添加修改一次需要花费资源越来越大,可以设置成map中多个map,然后计算hash取模,加锁只加其中的一个小map。和数据库的分区类似。分离锁,只对一块数据中的一个区锁定。
并发类介绍----工具类
    信号量,semaphore:如最多5个信号,业务运算时候需要先得到信号(acquire),在运算,结束后再release。有些像连接池一样,限制的计算量。
    关卡,barrier,实现类:CyclicBarrier,执行完的线程在最后等待,等待最后的线程执行完,然后大家一起结束。
    闭锁,latch, CountDownLatch:等到所有资源集合完毕,等待的线程才能统一的都运行。
 
并发类介绍----线程池工具类
    当创建很多运行时间很多的线程时候,jvm为分配资源的代价越来越高,线程池和数据库连接池类似
    Executors 类下的静态方法,
newFixedThreadPool(int nThreads);--定长线程池。
newCachedThreadPool(); --根据系统需要创建,然后重用等方法。
   缓慢的劣质化:
当用池后,你的线程不会无限的增长导致内存溢出,在你的控制下,你的系统负载很高时,用户提交的数据在你的jvm中被阻塞,后来又在操作系统层面缓存提交,操作系统不够后只能在路由器缓存,最后路由器就timeout给用户。
 
并发测试:
   垃圾回收会影响你的测试报告,禁止测试时候执行垃圾回收:-verbose:gc
   方法首先运行使用解释字节码方式执行,足够频繁时候会动态编译, 打印编译信息,-XX:+PrintCompilation     
   Jdk有client,server 多种运行模式,发布时候肯定运行于server模式下,该模式下更擅长优化死代码:-server
 
公式定律
   Amdahl定律:当计算资源必须使用串行化占比,然后计算出可提升性能的公式:
   定制java 线程池大小:等待时间(WT)与服务时间(ST)之间的比例。如果我们将这一比例称之为 WT/ST,那么对于一个具有 N 个处理器的系统,需要设置大约 N*(1+WT/ST) 个线程来保持处理器得到充分利用
 
happen-before :
   编译器为了提高多线程性能,会对代码进行重新排序,基于happen-before 规则才能确定代码执行的先后顺序。
   1.单线程规则:同一个线程中,书写在前面的操作happen-before书写在后面的操作。这条规则是说,在单线程 中操作间happen-before关系完全是由源代码的顺序决定的。
   2.对锁的unlock操作happen-before后续的对同一个锁的lock操作。这里的“后续”指的是时间上的先后关系,unlock操作发 生在退出同步块之后,lock操作发生在进入同步块之前。必须对同一个变量的 所有 读写同步,才能保证不读取到陈旧的数据,仅仅同步读或写是不够的 。  
   3.如果操作A happen-before操作B,操作B happen-before操作C,那么操作A happen-before操作C。称为传递规则。
   可参考: http://www.iteye.com/topic/260515 
 


已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [java 并发 编程] 推荐:

Java并发编程基础

- - 并发编程网 - ifeve.com
并发是一种能并行运行多个程序或并行运行一个程序中多个部分的能力. 如果程序中一个耗时的任务能以异步或并行的方式运行,那么整个程序的吞吐量和可交互性将大大改善. 现代的PC都有多个CPU或一个CPU中有多个核. 是否能合理运用多核的能力将成为一个大规模应用程序的关键. 进程是以独立于其他进程的方式运行的,进程间是互相隔离的.

java 并发编程 synchronized

- - Java - 编程语言 - ITeye博客
同步原语--synchronized. synchronized(class)很特别,它会让另一个线程在任何需要获取class做为monitor的地方等待.class与this做为不同的监视器可以同时使用,不存在一个线程获取了class,另一个线程就不能获取该class的一切实例.. ->线程各自获取monitor,不会有等待..

Java并发编程【1.2时代】

- - 并发编程网 - ifeve.com
         本文介绍了Java原生的多线程技术(1.2),通过详细介绍wait和notify相关的机制、基础的多线程技术以及基于这些技术的等待超时、线程间的通信技术和线程池高阶技术,最后通过一个基于线程池的简单文本web服务器—MollyServer,来阐明多线程带来好处. 通过介绍这些技术,展示了在没有使用Java并发包的时代(1.5-)是如何完成Java的多线程编程,为理解Java5提供了良好帮助.

java并发编程下变量可见行分析

- - ITeye博客
 在ubutun双核cpu下,默认不加任何jvm参数执行. 输出如下: 主线程执行完之后,子线程一直在执行,为什么子线程没有获取到主线程修改done之后的变量值呢. 我们再设置下jvm的参数为 -client,则子线程能够获取主线程修改done之后的值,正常执行完. 也就是moren ubutun下默认jvm启动是-server 服务器默认启动的,那么-server启动跟client启动有什么区别呢.

java并发编程实践学习笔记

- - zzm
    原子操作:原子为不可再分操作.    Violation :可见关键字.    Synchronized:内部隐示锁 .    ReentrantLock:显示锁 .    ReentrantReadWriteLock:读写锁 . jmm(java内存模型):. 线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递 均需要通过主存完成.

Java并发编程-生成唯一序列号

- - 编程语言 - ITeye博客
package com.league.idgenerate; /** * * ID生成器接口, 用于生成全局唯一的ID流水号 * * @author Ivan.Ma */ public interface IdGenerator {. * 生成下一个不重复的流水号. package com.league.idgenerate; /** * ID生成器的配置接口 * @author Ivan.Ma */ public interface IdGeneratorConfig {.

关于Java并发编程的总结和思考

- - ImportNew
并发其实是一种解耦合的策略,它帮助我们把做什么(目标)和什么时候做(时机)分开. 这样做可以明显改进应用程序的吞吐量(获得更多的CPU调度时间)和结构(程序有多个部分在协同工作). 做过Java Web开发的人都知道,Java Web中的Servlet程序在Servlet容器的支持下采用单实例多线程的工作模式,Servlet容器为你处理了并发问题.

Java编程规范

- - Web前端 - ITeye博客
本文档的编写从简,绝大多数内容以条款或者表格形式列出,不做过多的补充说明,代码格式规范遵循eclipse的默认编码规范要求. •    简单,易执行. 1.    名字含义要明确,做到见名知义,如: User,Role, UserManager. 2.    尽量使用英文名字作为变量名,如果要使用中文,请写上备注.

java编程风格指南

- - 行业应用 - ITeye博客
受不了的可以直接到以下网址查看. 作者:Hawstein 出处:http://hawstein.com/posts/google-java-style.html 声明:本文采用以下协议进行授权: 自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0 ,转载请注明作者及出处.

面向GC的Java编程

- - 并发编程网 - ifeve.com
Java程序员在编码过程中通常不需要考虑内存问题,JVM经过高度优化的GC机制大部分情况下都能够很好地处理堆(Heap)的清理问题. 以至于许多Java程序员认为,我只需要关心何时创建对象,而回收对象,就交给GC来做吧. 甚至有人说,如果在编程过程中频繁考虑内存问题,是一种退化,这些事情应该交给编译器,交给虚拟机来解决.