并发模型—共享内存模型(线程与锁)示例篇

共享内存模型,顾名思义就是经过共享内存来实现并发的模型,当多个线程在并发执行中使用共享资源时如不对所共享的资源进行约定或特殊处理时就会出现读到脏数据、无效数据等问题;而为了决解共享资源所引发的这些问题,Java中引入了同步、锁、原子类型等这些用于处理共享资源的操做;
  在本篇文章中,将经过几个Demo来介绍Java的synchronized、lock、atomic相关类等,Java的共享内存并发模型也就体如今同步(synchronized)、锁(lock)等这些实现上; java

同步:
  Demo中开启两个线程调用一个计数器,这时计数器成了两个线程的共享资源,两个线程都在竞争共享资源发生了竟态条件,当不对竟态条件进行处理时获得的数据就多是有异常的不正确的;编程

 1 /**
 2  * Created by linx on 2015-05-12.
 3  */
 4 public class Counter { 
 6     private int count = 0; 
 8     public  void increment() {
 9         ++count;
10     }
12     public int getCount() {
13         return count;
14     }
15 }
16 /**
17  * Created by linx on 2015-05-12.
18  */
19 public class CountThread extends Thread {
20 
21     private Counter counter;
22     public CountThread(Counter counter) {
23         this.counter = counter;
24     }
25     @Override
26     public void run() {
27         for (int i = 0; i < 5000; i++) {
28             counter.increment();
29         }
30     }
31 }
32 /**
33  * Created by linx on 2015-05-12.
34  */
35 public class CountMain {
36 
37     public static void main(String[] args) throws InterruptedException {
38 
39         Counter counter = new Counter();
40         AtomicCounter atomicCounter=new AtomicCounter();
41         CountThread t1 = new CountThread(counter);
42         CountThread t2 = new CountThread(counter);
43         t1.start();
44         t2.start(); 
45         t1.join();
46         t2.join();
47         System.out.println(counter.getCount());
48     } 
49 }

我在执行这代码的时候几乎每次获得的结果都是不同的,结果以下:

由于这里有竟态条件因此结果是不可预测的;
解决竟态条件的方法是对锁竞争的资源进行加锁同步,在java中能够用synchronized或lock等锁;
如今咱们再修改计数器的代码:多线程

public synchronized void increment() {
  ++count;
}

这里咱们只是在increment方法声明处加了synchronized关键字,这时候咱们在执行程序,如今每次咱们获得结果都会是10000,
由于咱们解决了竟态条件,同一时间就会有一个线程会进入到increment方法执行,因此这时候获得的就是正确的结果;并发


在这里咱们只是把上面Demo中的synchronized换成Lock对象,获得的结果仍是相同的;分布式

/**
 * Created by linx on 2015-05-12.
 */
public class Counter {
    private int count = 0;
    Lock lock=new ReentrantLock();
    public  void increment() {
        lock.lock();
        try {
            ++count;
        }finally {
            lock.unlock();
        }
    }
    public int getCount() {
        return count;
    }
}  

这里咱们显示的使用了显试的ReentrantLock锁对象给increment方法中的代码块进行了加锁,其余synchronized也是对方法进行了加锁,不过它使用的是对象的内置锁;
原子类型
    咱们上面的Demo只因此没有同步或加锁时会出现问题是由于++count不是原子的,它实际上是read-modify-write三个操做,只要能保证increment为原子方法那么这里也就不是出现问题了,如今咱们吧count改成原子类型;ide

/**
 * Created by linx on 2015-05-12.
 */
public class AtomicCounter {
    private AtomicInteger count=new AtomicInteger();
    public  void increment() {
        count.incrementAndGet();
    } 
    public AtomicInteger getCount() {
        return count;
    }
}

这个计数器类咱们不进行任何同步或加锁都不会出现问题,由于increment方法是原子的。性能

模型优缺点
  优势:内存共享模型或称线程与锁模型使用面很广,并且如今几乎每一个操做系统中也存在这种模型,因此也算很是见的一种模型。 测试

  缺点:线程与锁模型存在的一些问题有,没有直接支持并发、没法或难于实现分布式共享内存的系统,线程与锁模型有很是很差的地方就是难于测试,在多线程编程中不少时候不经意间就出现问题了这时都还不知道,并且当忽然出现了Bug这时每每咱们也难于重现这个Bug,共享内存模型又是不可创建数学模型的,其中有很大的不肯定性,而不肯定性就说明可能掩藏着问题,人的思惟也只是单线程的;this

还有因为建立线程也是很是消耗资源的,而多线程间的竟态条件、锁等竞争若是处理很差也是会很是影响性能的;atom

 

 文章首发地址:Solinxhttp://www.solinx.co/archives/190

相关文章
相关标签/搜索