Android多线程--线程锁总结

最近准备将自己的学习笔记记录下来,养成写博客的习惯,一下内容是根据书上和网上资料整合而成,同时也有一部分自己的理解。

一、synchronize同步锁(内置锁)
为了防止多线程同时操作同一个位置,可以上锁的有对象和class。

public class synchronizedDemo{
//同步方法
public synchronized void method{
//doSomething
}
//同步块
synchronizedthis){
//doSomething
}
//同步class对象
synchronized(synchronizedDemo.class){
//doSomething
}
//同步静态方法
public synchronized  static void method{
//doSomething
}
}

同步方法和同步块锁的是对象,同步class和同步静态方法锁的是class对象。
锁class对象是作用于多线程访问同一个synchronized代码块时
而锁对象是作用于多线程访问同一个对象的synchronized代码块时

二、ReentrantLock(显示锁)
java6.0后增加的新的机制
和synchronize不同的是,synchronized获取和释放都在同一个代码块,而它更加灵活,可以自由控制锁的获取和释放。
同时可以提供轮训所、定时锁、公平锁和非公平锁。
lock()—>获取锁;
tryLock()—>尝试获取锁;
tryLock(long timeout ,timeUnit Unit)—>指定获取超时的时间
unLock()—>释放锁
newCondition()—> 获取锁的condition
ps:显示锁Lock之后必须解锁,不然会导致死锁,这也是显示锁没有完成代替synchronized的原因。

reentrantlock还有一个非常重要的方法:newCondition(),作用于锁上的一个条件,来完成wait()、notify()、notifyall()等方法。

下面是通过reentrantLock完成的一个有界的阻塞队列

public class MyArrayBlockingQueue {
    private final T[] items;
    //显示锁
    private final Lock lock = new ReentrantLock();
    //队满的条件
    private Condition notFull = lock.newCondition();
    //队空的条件
    private Condition notEmpty = lock.newCondition();
    //头部
    private int head;
    //尾部
    private int tail;
    //当前数据个数
    private int count;

    public MyArrayBlockingQueue(int MaxSize) {
        items = (T[]) new Object[MaxSize];
    }

    public MyArrayBlockingQueue() {
        this(10);
    }

    public void put(T t) {
        lock.lock();
        try {
            while (count == getCapacity()) {
                System.out.println("数据已满,请等待");
                notFull.wait();
            }
            items[tail] = t;
            if (++tail == getCapacity())
                tail = 0;
            ++count;
            notEmpty.signalAll();//唤醒等待数据的线程
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public T take() {
        lock.lock();
        try {
            while (count == getCapacity()) {
                System.out.println("暂无数据,请等待");
                notEmpty.wait();
            }
            T ret = items[head];
            items[head] = null;
            if (++head == getCapacity())
                head = 0;
            --count;
            notFull.signalAll();//唤醒添加数据的线程
            return ret;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return null;
    }

    public int getCapacity() {
        return items.length;
    }

    public int size() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }
}

三、信号量Semaphore
他的本质是”共享锁“,线程必须先获取信号量(acquire)才能继续执行,否则将等待。
在执行完成之后,必须释放信号(release),其他线程才能取得信号。
示例代码

public static void main(String[] args) {
                // 线程池
ExecutorService exec = Executors.newCachedThreadPool();
                // 只能3个线程同时访问
                final Semaphore semp = new Semaphore(3);
                 // 模拟5个客户端访问
                 for (int index = 0; index < 5; index++) {
                              final int NO = index;
                              Runnable run = new Runnable() { 
                                  public void run() {
                                  try {
                                                                    // 获取许可
                                                                                            semp.acquire();
                                                                    System.out.println("Accessing: " + NO);
                                                                    Thread.sleep((long) (Math.random() * 10000));
                                                                    // 访问完后,释放
                                                                    semp.release();
                                                                    System.out.println("-----------------"+semp.availablePermits());
                                                            } catch (InterruptedException e) {
                                                                    e.printStackTrace();
                                                            }
                                                  }
                                      };
                      exec.execute(run);
             }
             // 退出线程池
             exec.shutdown();
       }
} 

执行结果如下:
Accessing: 0
Accessing: 1
Accessing: 2
—————–0
Accessing: 4
—————–1
Accessing: 3

四、循环栅栏CyclicBarrier
CyclicBarrier是一个同步辅助类,允许N个线程相互等待(await),直到达到某个公共点,再一起继续执行;因为可以重用,所以称它为循环Barrier.
示例:赛跑时,等待所有人都准备好时,才起跑.

public class CyclicBarrierTest {  
  2.   
  3.     public static void main(String[] args) throws IOException, InterruptedException {  
  4.         //如果将参数改为4,但是下面只加入了3个选手,这永远等待下去  
  5.         //Waits until all parties have invoked await on this barrier.   
  6.         CyclicBarrier barrier = new CyclicBarrier(3);  
  7.   
  8.         ExecutorService executor = Executors.newFixedThreadPool(3);  
  9.         executor.submit(new Thread(new Runner(barrier, "1号选手")));  
  10.         executor.submit(new Thread(new Runner(barrier, "2号选手")));  
  11.         executor.submit(new Thread(new Runner(barrier, "3号选手")));  
  12.   
  13.         executor.shutdown();  
  14.     }  
  15. }  
  16.   
  17. class Runner implements Runnable {  
  18.     // 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)  
  19.     private CyclicBarrier barrier;  
  20.   
  21.     private String name;  
  22.   
  23.     public Runner(CyclicBarrier barrier, String name) {  
  24.         super();  
  25.         this.barrier = barrier;  
  26.         this.name = name;  
  27.     }  
  28.   
  29.     @Override  
  30.     public void run() {  
  31.         try {  
  32.             Thread.sleep(1000 * (new Random()).nextInt(8));  
  33.             System.out.println(name + " 准备好了...");  
  34.             // barrier的await方法,在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。  
  35.             barrier.await();  
  36.         } catch (InterruptedException e) {  
  37.             e.printStackTrace();  
  38.         } catch (BrokenBarrierException e) {  
  39.             e.printStackTrace();  
  40.         }  
  41.         System.out.println(name + " 起跑!");  
  42.     }  
  43. }  

输出结果:
3号选手 准备好了…
2号选手 准备好了…
1号选手 准备好了…
1号选手 起跑!
2号选手 起跑!
3号选手 起跑!

五、闭锁CountDownLatch
CountDownLatch也是同步辅助类。他的作用是使一个或多个线程等待(await),直到所有线程都完成某个事件,调用(countDown)后,才能继续执行。
示例代码:

  1. public class countDownlatchTest {  
  2.     public static void main(String[] args) throws InterruptedException {  
  3.         CountDownLatch countDownLatch = new CountDownLatch(5);  
  4.         for(int i=0;i<5;i++){  
  5.             new Thread(new readNum(i,countDownLatch)).start();  
  6.         }  
  7.         countDownLatch.await();  
  8.         System.out.println("等待结束,继续执行");
  9.        //dosomething  
  10.     }  
  11.   
  12.     static class readNum  implements Runnable{  
  13.         private int id;  
  14.         private CountDownLatch latch;  
  15.         public readNum(int id,CountDownLatch latch){  
  16.             this.id = id;  
  17.             this.latch = latch;  
  18.         }  
  19.         @Override  
  20.         public void run() {  
  21.             synchronized (this){  
  22.                 System.out.println("id:"+id);  
  23.                 latch.countDown();  
  24.                 System.out.println("线程组任务"+id+"结束,其他任务继续");  
  25.             }  
  26.         }  
  27.     }  
  28. }  

输出结果:
id:1
线程组任务1结束,其他任务继续
id:0
线程组任务0结束,其他任务继续
id:2
线程组任务2结束,其他任务继续
id:3
线程组任务3结束,其他任务继续
id:4
线程组任务4结束,其他任务继续
等待结束,继续执行

cyclicbarrier countdownlatch 区别:(个人见解)
1、很明显的区别:cyclicbarrier可重用,后者不行。
2、前者偏向于等待所有玩家(线程)到齐之后,一起去做后续事件
后者偏向于等待所有玩家(线程)都达成某个条件后,继续做后续事件。

你可能感兴趣的:(Android)