java并发编程

  三个概念的理解:程序、进程和线程

    程序:静态实体

    进程:动态实体,存于内存,又叫任务,是程序的运行时期

    线程:进程创建的更小粒度

  编写线程安全的代码,本质上就是管理对状态的访问,而且通常都是共享的、可变的状态。所谓共享是指一个变量被多个线程访问;所谓可变是指变量的值在其生命周期内可以改变。

  线程安全这个性质取决于程序中如何使用对象,而不是对象完成了什么。一开始就将类设计为线程安全的,比在后期修改他更容易。

一、概念

  1、线程安全类:当多个线程访问一个类时,如果不用考虑线程在运行时的调度和交替执行,并且不用额外的同步机制作为协调,这个类的行为仍然是正确的,那么我们说这个类为线程安全的。

    示例:无状态类——它不包含域也没有引用其他类的域。无状态对象永远是线程安全的。

    解释:无状态对象只有一些方法,方法内部的局部变量会存到相应线程的堆栈中,每个线程的堆栈是独立的。

  2、原子性:当其他线程想要访问查看或者修改一个状态时,必须在我们的线程开始之前或者完成之后,而不能在操作过程中。

     原子操作:要么都执行,要么都不执行

     原子变量类:java.util.concurrent.atmoic里提供的原子变量类。类的小工具包,支持在单个变量上解除锁的线程安全编程。

  3、java的内置的原子性机制——锁:synchronized块。块包含两部分:锁对象的引用,这个锁要保护的代码块。

    3.1内部锁

    3.2重进入

       线程请求自己占有的锁时,请求会成功。

  4、用锁来保护状态

    操作共享状态的复合操作必须是原子操作。复合操作会在完整的运行期间占有锁,以确保其行为是原子的。

  5、活跃度与性能

    过于强调安全就会出现性能下降,过度强调安全,就会导致不必要的等待。

二、共享对象

   1、可见性

     为了确保跨线程写入内存的可见性,必须使用同步机制。只要数据需要跨线程共享,就进行恰当的同步。

     1.1过期数据

        没有进行恰当的线程同步机制,导致一个线程对共享数据的修改,并不能保证其余的线程是可见的。

     1.2非原子的64位操作

        java的存储模型要求存储和读取操作都为原子的,但是对于非volatile的long和double变量,JVM允许将64位的读或写划分为两个32位的操作。因此,在多线程中共享、可变的long和double变量也可能是不安全的,除非将他们声明为volatile类型,或者用锁保护起来。

     1.3锁和可见性

        锁不仅仅是关于同步和互斥的,也是关于内存可见性的。为了保证所有线程都能看到共享变量的最新值,读取和写入线程必须使用公共的锁进行同步。

     1.4volatile变量

        volatile相比锁而言,只是一种轻量级的同步机制。

        volatile变量的典型应用:检查状态标记,以确定是否退出一个循环。

        volatile也有缺点:volatile的语义并不能保证自增操作是原子操作。加锁可以保证原子性和可见性,volatile变量只能保证可见性

   2、线程封闭

      2.1栈限制

        栈限制是线程限制的一种特例,在栈限制中,只能通过本地变量才可以触及对象。每个线程都有自己的堆栈,本地变量基本上都存储与自己的堆栈,每个线程的堆栈是不会有冲突的,其他线程是不会访问到的,本地变量是线程封闭的。

      2.2ThreadLoacl

        一种维护线程限制的更加规范的形式,它允许将每个线程与持有数值的对象关联起来。ThreadLocal提供了get和set访问器,为每个使用他的线程维护一份单独的拷贝。其实和线程池差不多。

    3、不可变性

      不可变对象永远是线程安全的。不可变对象是简单的。

      不可变对象的条件:

        ①他的状态不能再创建后修改(对“状态”的理解:对象的引用)

        ②所有的域都是final类型

      使用volatile发布不可变对象:用不可变容器再加上volatile关键字发布不可变对象。具体代码如下    

 1 @immutable
 2 public class OnerValueCache {
 3     
 4     private final BigInteger lastNumBigInteger;
 5     private final BigInteger [] lastFactorsBigIntegers;
 6     
 7     public OnerValueCache(BigInteger num,BigInteger[] factors){
 8         lastNumBigInteger=num;
 9         lastFactorsBigIntegers=Arrays.copyOf(factors,factors.length);
10     }
11     
12     public BigInteger[] getFactors(BigInteger num){
13         if(lastNumBigInteger==null||!lastNumBigInteger.equals(num)){
14             return null;
15         }
16         return Arrays.copyOf(lastFactorsBigIntegers, lastFactorsBigIntegers.length);
17     }
18 }
View Code
 1 @ThreadSafe
 2 public class VolatileCachedFactorizer implements Servlet{
 3   private volatile OnerValueCache cache=new OnerValueCache(null,null); 
 4   public void service(){
 5     BigInteger i =extractFromRequest(req);
 6     BigInteger Factors=cache.getFactors(i);
 7     if(factors==null){
 8        factors=factor(i);
 9        cache=new OnerValueCache(i,factors);  
10     }
11     encodeIntResponse(resp,factors);
12   }   
13 }    
View Code
原文地址:https://www.cnblogs.com/sylz/p/5959901.html