`
liang3307
  • 浏览: 13237 次
  • 性别: Icon_minigender_1
  • 来自: 浙江
社区版块
存档分类
最新评论

java并发编程实践学习笔记

阅读更多

为啥需要并发:

      个人英雄主义,单人独写xx软件的传奇,回味孤独英雄的寂寞。
       系统运行也不是单个计算机或现在的单核cpu能够很好解决运行:系统需要 显示多机多cpu负载计算,为了响应当前的低碳生活,我们需要提高单机的计算能 力,更好的学习设计并发。
  
关键字:
    原子操作:原子为不可再分操作。
   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
分享到:
评论

相关推荐

    java并发编程实践笔记

    ### Java并发编程实践笔记知识点详解 #### 一、保证线程安全的方法 1. **不要跨线程访问共享变量:** 当多个线程共享某个变量时,若其中一个线程修改了该变量,其他线程若没有正确同步,则可能读取到错误的数据。...

    Java并发编程学习笔记.rar

    这本"Java并发编程学习笔记"可能是作者在深入研究Java并发特性、工具和最佳实践过程中积累的心得体会。下面,我们将根据这个主题,探讨一些关键的Java并发编程知识点。 1. **线程与进程**:在多任务环境中,线程是...

    Java并发实践-学习笔记

    这份"Java并发实践-学习笔记"涵盖了这个关键主题,旨在帮助开发者深入理解和掌握Java中的并发机制。以下是对这份笔记可能包含的一些核心知识点的详细阐述: 1. **Java并发基础**:首先,笔记可能会介绍Java并发的...

    JAVA并发编程实践-构建执行程序块-学习笔记

    JAVA并发编程实践-构建执行程序块-学习笔记 JAVA并发编程实践是指在JAVA编程语言中,使用多线程、并发编程来实现高效、可靠的程序执行。构建执行程序块是指在并发编程中,使用线程安全的类来管理状态,以确保程序的...

    JAVA并发编程实践-线程执行-学习笔记

    总的来说,Java并发编程实践中的任务执行是一个涉及线程调度、线程池管理、任务生命周期控制、结果处理等多个方面的复杂主题。理解和掌握这些概念和技术,能够帮助开发者编写出更加高效、可靠的并发程序。

    JAVA并发编程实践-线程池-学习笔记

    Java并发编程实践中的线程池是一个关键的概念,它在多线程编程中扮演着至关重要的角色,有效地管理和调度线程资源,以提高系统的性能和效率。线程池通过复用已存在的线程来减少线程的创建和销毁开销,避免了频繁的上...

    JAVA并发编程实践-线程安全-学习笔记

    在Java并发编程中,线程安全是一个至关重要的概念,它涉及到多线程环境下对共享数据的正确管理和访问。线程安全意味着当多个线程同时访问一个对象或数据时,对象的状态能够保持一致性和完整性,不会因为并发导致数据...

    Java Concurrency In Practice Learning Note

    《Java并发编程实践学习笔记》是一份深入探讨Java并发编程的资源,主要涵盖了在实际开发中如何有效地管理和利用多线程。这篇博文链接虽然没有提供具体的内容,但从标题来看,我们可以推断它会讨论Java并发编程的最佳...

    JAVA并发编程实践-线程的关闭与取消-学习笔记

    在Java并发编程中,线程的关闭和取消是一项重要的任务,因为不正确的处理可能导致数据不一致、资源泄漏等问题。在Java中,强制停止线程并不是一个推荐的做法,因为这可能会导致系统状态的不稳定。传统的`Thread.stop...

    JAVA并发编程实践-线程对象与组合对象-学习笔记

    使用java.util.concurrent类库构造安全的并发应用程序的基础。共享其实就是某一线程的数据改变对其它线程可见,否则就会出现脏数据。

    【Java技术资料】-(机构内训资料)Java并发体系学习思维笔记

    这份机构内训资料,通过“Java并发体系学习思维笔记”,为我们揭示了Java并发编程的核心概念、最佳实践以及常见问题的解决策略。 首先,我们需要理解Java并发的基础,这包括线程的创建与管理。Java提供了两种主要的...

    Java面试题和学习笔记

    Linux面试专题及答案+ActiveMQ消息中间件面试专题+Java基础面试题+MySQL性能优化的21个最佳实践+微服务面试专题及答案+深入理解java虚拟机+设计模式面试专题及答案+开源框架面试专题及答案+并发编程及答案+Spring...

    Java编程思想学习笔记

    在讨论Java编程思想学习笔记时,首先需要了解的是Java语言的平台无关性,而这一特性正是通过Java虚拟机(JVM)得以实现的。JVM作为Java程序设计的关键组成部分,对于Java开发人员来说是必须掌握的基础知识。在该学习...

    Java基础尚硅谷宋红康学习笔记

    10. **Java并发编程**:包括线程池、锁机制(如synchronized、ReentrantLock)、并发容器(如ConcurrentHashMap、CopyOnWriteArrayList)以及并发工具类(如CountDownLatch、CyclicBarrier)。 这些是Java基础知识...

    JUC并发编程学习笔记(硅谷)

    Java并发编程是Java开发中的重要领域,特别是在大型分布式系统或者高并发应用中,对线程安全和性能优化的理解与实践至关重要。"JUC并发编程学习笔记(硅谷)"很可能包含了关于Java并发工具集(Java Util Concurrency, ...

    Java学习资料-并发编程.zip

    首先,"Java并发编程笔记"这部分内容可能涵盖了以下几个关键知识点: 1. **线程基础**:线程的创建、启动、中断和销毁,以及如何使用`Thread`类和`Runnable`接口来创建线程。 2. **并发控制**:包括`synchronized`...

    Java入门学习笔记

    这份"Java入门学习笔记"涵盖了imooc网站上Java入门课程的三个赛季的内容,旨在为初学者提供一个全面的学习资源。 笔记的第一部分是"Java入门第一季学习笔记",它可能包括Java的基础概念和语法。这部分可能会讲解...

Global site tag (gtag.js) - Google Analytics