并发高级知识

1.synchronized void f()

2.使用Lock,更好的管理异常;尝试获取锁一段时间;

private Lock lock = new ReentrantLock();
  public int next() {
    lock.lock();
    try {
      ++currentEvenValue;
      Thread.yield(); // Cause failure faster
      ++currentEvenValue;
      return currentEvenValue;
    } finally {
      lock.unlock();
    }

尝试获取锁最终未获取锁:

captured = lock.tryLock(2, TimeUnit.SECONDS);

更细粒度的控制;

3.volitail保证了可视性(尤其在多处理器系统)

4.原子性变量类:AtomicInteger,AtomicLong,AtomicReference

重要方法:

public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

这是一个本地方法:

 public final native boolean compareAndSwapInt(Object obj, long l, int i, int j);

在硬件层面保证了原子性

5.临界区,也被称为同步代码块

 synchronized(this) {
      p.incrementX();
      p.incrementY();
      temp = getPair();
    }

优点:相比同步方法,控制粒度更小,其他线程能更多地访问

注意:synchronized块必须给定一个在其上进行同步的对象,最合理的方式是使用其方法正在被调用的当前对象,如果获得了synchronized块的锁,那么该对象其他的synchronized方法和临界区就不能被调用了

6,线程本地存储:ThreadLocal

 private static ThreadLocal<Integer> value =
    new ThreadLocal<Integer>() {
      private Random rand = new Random(47);
      protected synchronized Integer initialValue() {
        return rand.nextInt(10000);
      }
    };
public static void increment() {
    value.set(value.get() + 1);
  }

注意,ThreadLocal并不是一个Map<Thread,value>,而是在当前Thread线程的一个成员变量:

public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
ThreadLocal.ThreadLocalMap threadLocals = null;

7.终结任务

Thread.interrupt()

Executor.shutdownNow()--interrupte它启动的所有线程

中断某一个单一任务:

 Future<?> f = exec.submit(r);
    TimeUnit.MILLISECONDS.sleep(100);
    print("Interrupting " + r.getClass().getName());
    f.cancel(true); // Interrupts if running

8.线程之间的协作:某些部分必须在其他部分被解决之前解决

wait();

notifyAll();唤醒等待这个锁的所有任务

notify();只有一个等待这个锁的任务会被唤醒

上面这三个方法都是Object类中的方法

9.生产者-消费者与队列

wait与notify可以进行生产者-消费者的模型构建,以一种低级的方式解决了任务互操作的问题,即每次交互时都握手。

更高的抽象级别,是使用同步队列来解决任务协作问题,同步队列在任何时刻都只允许一个任务插入或移除元素。

java.util.concurrent.BlockingQueue接口中提供了这个队列,通常可以使用无界队列LinkedBlockingQueue(通过使用ReentrantLock加锁),还可以使用ArrayBlockingQueue,它具有固定的尺寸。

当队列为空时,可以自动挂起消费者任务,当队列中有元素时,可以自动恢复消费者任务,比起wait和notity,这种方式简单而可靠(消除了类之间的耦合)。

一个烤面包的示例:

class Toast {
  public enum Status { DRY, BUTTERED, JAMMED }
  private Status status = Status.DRY;
  private final int id;
  public Toast(int idn) { id = idn; }
  public void butter() { status = Status.BUTTERED; }
  public void jam() { status = Status.JAMMED; }
  public Status getStatus() { return status; }
  public int getId() { return id; }
  public String toString() {
    return "Toast " + id + ": " + status;
  }
}

class ToastQueue extends LinkedBlockingQueue<Toast> {}

class Toaster implements Runnable {
  private ToastQueue toastQueue;
  private int count = 0;
  private Random rand = new Random(47);
  public Toaster(ToastQueue tq) { toastQueue = tq; }
  public void run() {
    try {
      while(!Thread.interrupted()) {
        TimeUnit.MILLISECONDS.sleep(
          100 + rand.nextInt(500));
        // Make toast
        Toast t = new Toast(count++);
        print(t);
        // Insert into queue
        toastQueue.put(t);
      }
    } catch(InterruptedException e) {
      print("Toaster interrupted");
    }
    print("Toaster off");
  }
}

// Apply butter to toast:
class Butterer implements Runnable {
  private ToastQueue dryQueue, butteredQueue;
  public Butterer(ToastQueue dry, ToastQueue buttered) {
    dryQueue = dry;
    butteredQueue = buttered;
  }
  public void run() {
    try {
      while(!Thread.interrupted()) {
        // Blocks until next piece of toast is available:
        Toast t = dryQueue.take();
        t.butter();
        print(t);
        butteredQueue.put(t);
      }
    } catch(InterruptedException e) {
      print("Butterer interrupted");
    }
    print("Butterer off");
  }
}

// Apply jam to buttered toast:
class Jammer implements Runnable {
  private ToastQueue butteredQueue, finishedQueue;
  public Jammer(ToastQueue buttered, ToastQueue finished) {
    butteredQueue = buttered;
    finishedQueue = finished;
  }
  public void run() {
    try {
      while(!Thread.interrupted()) {
        // Blocks until next piece of toast is available:
        Toast t = butteredQueue.take();
        t.jam();
        print(t);
        finishedQueue.put(t);
      }
    } catch(InterruptedException e) {
      print("Jammer interrupted");
    }
    print("Jammer off");
  }
}

// Consume the toast:
class Eater implements Runnable {
  private ToastQueue finishedQueue;
  private int counter = 0;
  public Eater(ToastQueue finished) {
    finishedQueue = finished;
  }
  public void run() {
    try {
      while(!Thread.interrupted()) {
        // Blocks until next piece of toast is available:
        Toast t = finishedQueue.take();
        // Verify that the toast is coming in order,
        // and that all pieces are getting jammed:
        if(t.getId() != counter++ ||
           t.getStatus() != Toast.Status.JAMMED) {
          print(">>>> Error: " + t);
          System.exit(1);
        } else
          print("Chomp! " + t);
      }
    } catch(InterruptedException e) {
      print("Eater interrupted");
    }
    print("Eater off");
  }
}

public class ToastOMatic {
  public static void main(String[] args) throws Exception {
    ToastQueue dryQueue = new ToastQueue(),
               butteredQueue = new ToastQueue(),
               finishedQueue = new ToastQueue();
    ExecutorService exec = Executors.newCachedThreadPool();
    exec.execute(new Toaster(dryQueue));
    exec.execute(new Butterer(dryQueue, butteredQueue));
    exec.execute(new Jammer(butteredQueue, finishedQueue));
    exec.execute(new Eater(finishedQueue));
    TimeUnit.SECONDS.sleep(5);
    exec.shutdownNow();
  }
}

10.死锁

必须同时满足4个条件:

1.互斥条件:至少有一个资源不能共享

2.至少有一个任务持有一个资源且等待别的资源

3.资源不能被任务抢占

4.必须有循环等待

防止死锁,只需破坏其中一个即可,最容易的方法是破坏第四个条件

11.CountDownLatch

同步多个任务,CountDownLatch设置一个初始计数值,任务调用countDown()减小计数值,直到为0

12.CyclicBarrier

创建一组任务,当这组任务都完成时才能进行下一步

13.DelayQueue

是一种无界阻塞队列,其中的元素只有在到期时才能被取走

14.PriorityBlockingQueue

优先级队列

15.免锁容器

CopyOnWriteArrayList:对容器的修改和读取可以同时发生

存储数组:

private volatile transient Object[] array;//volatile保证可见性

add方法:

public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();//使用锁
        try {
            Object[] elements = getArray();//获取旧的数据的副本
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);//更新数据
            return true;
        } finally {
            lock.unlock();
        }
    }

CopyOnWriteArraySet:借助CopyOnWriteArrayList实现免锁

ConcurrentHashMap<K, V>:用桶粒度的锁,避免了put和get中对整个map的锁定,尤其在get中,只对一个HashEntry做锁定操作

ConcurrentLinkedQueue

16.乐观加锁:即原子类中的compareAndSet()方法

17.ReadWriteLock:对经常读取的操作进行了优化,但是修改期间仍不能读取

 

posted on 2017-03-07 16:53  伪善者ql  阅读(202)  评论(0编辑  收藏  举报

导航