当前位置: 首页 > Thinking in Java > 正文

第21章 – 并发 – 共享资源,原子操作

第21章 – 并发 – 共享资源,原子操作

 

1. 针对每一个类,也有一个锁(作为类的class的一部分),所以,synchronized static 方法可以在类的

   范围内防止对static字段的并发访问.(P667)

 

   显然,类class的锁和该类对象的锁不是同一个锁,所以不要在普通对象上调用类的static方法.

 

2. 原子性可用于除了long和double之外的所有基本变量类型(char,int,short,byte,float,boolean)之上的”简单操作”.(P680)

 

   原子类,来自java.util.concurrent.atomic 包中的类,如AtomicInteger,AtomicReference<V>等.

   使用这些类可以获取比volatile更强的读写原子性保证.在多线程写入和读取这些变量时不存在中间状态,即一个线程

   更新这些变量之后,更新可以立即在别的线程中生效.不存在 变量值在一个线程中更新了,而另一个线程依旧读到变量的

   值更新之前的旧值 这种情况.

 

   可以使用原子类来替代同步(synchronized),以提高性能.

 

   但通常依赖于锁要更安全一些(要么是synchronized关键字,要么显式使用Lock对象)

package concurrency;

import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.*;

//不断产生偶数的类
public class AtomicIntegerTest implements Runnable
{
  private AtomicInteger i = new AtomicInteger(0);

  public int getValue()
  {
    return i.get();
  }

  private void evenIncrement()
  {
    i.addAndGet(2);
    //System.out.println(Thread.currentThread().getName() + ": " + i.get());
    
  }

  public void run()
  {
    while (true)
      evenIncrement();
  }

  public static void main(String[] args)
  {
    new Timer().schedule(new TimerTask()
    {
      public void run()
      {
        System.err.println("Aborting");
        System.exit(0);
      }
    }, 5000); // 设置5秒钟后程序自动停止
    
    
    ExecutorService exec = Executors.newCachedThreadPool();
    
    //使用两个线程同时运行
    AtomicIntegerTest ait = new AtomicIntegerTest();
    exec.execute(ait);
    exec.execute(ait);
    exec.shutdown();
    
    //这里循环检查得到的值,如果获取的不是偶数,则程序终止
    //因为这里不可能产生奇数,因此使用上面的Timer在5秒后结束程序
    while (true)
    {
      int val = ait.getValue();
      
      if ( val % 2 != 0 )
      {
        System.out.println("奇数==============================" + val);
        System.exit(0);
      }
    }
  }
}

 

3. 线程本地存储java.lang.ThreadLocal

   可以将各个线程中变量与其他线程隔离开来,保证当前线程中的这个变量不受其他线程的影响.

package concurrency;

// Automatically giving each thread its own storage.
import java.util.concurrent.*;

class Accessor implements Runnable
{
  private final int id;

  public Accessor(int idn)
  {
    id = idn;
  }

  public void run()
  {
    while (!Thread.currentThread().isInterrupted())
    {
      ThreadLocalVariableHolder.set(id);
      ThreadLocalVariableHolder.increment();
      System.out.println(this);
      Thread.yield();
    }
  }

  public String toString()
  {
    return "#" + id + ": " + ThreadLocalVariableHolder.get();
  }
}

public class ThreadLocalVariableHolder
{
  private static ThreadLocal<Integer> value = new ThreadLocal<Integer>()
                                            {
                                              // private Random rand = new Random(47);

                                              protected synchronized Integer initialValue()
                                              {
                                                return 20;
                                              }
                                            };

  public static void increment()
  {
    value.set(value.get() + 1);
  }

  public static int get()
  {
    return value.get();
  }

  public static void set(int i)
  {
    value.set(i);
  }

  public static void main(String[] args) throws Exception
  {
    ExecutorService exec = Executors.newCachedThreadPool();
    for (int i = 0; i < 5; i++)
      exec.execute(new Accessor(i));
    TimeUnit.MICROSECONDS.sleep(200); // Run for a while
    exec.shutdownNow(); // All Accessors will quit
  }
} 

 

赞 赏

   微信赞赏  支付宝赞赏


本文固定链接: https://www.jack-yin.com/coding/thinking-in-java/2144.html | 边城网事

该日志由 边城网事 于2015年03月18日发表在 Thinking in Java 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: 第21章 – 并发 – 共享资源,原子操作 | 边城网事
关键字: ,

第21章 – 并发 – 共享资源,原子操作 暂无评论

发表评论

快捷键:Ctrl+Enter