美文网首页
共享受限资源及锁

共享受限资源及锁

作者: 魏杨 | 来源:发表于2018-07-24 20:13 被阅读0次

    [TOC]

    1.不正确的访问资源

    懒汉单例模式,线程不安全

    public class SingletonDemo1 {
        private static SingletonDemo1 instance;
        private SingletonDemo1(){}
        public static SingletonDemo1 getInstance(){
            if (instance == null) {
                instance = new SingletonDemo1();
            }
            return instance;
        }
    }
    

    2.锁(synchronized)

    public class SingletonDemo2 {
        private static SingletonDemo2 instance;
        private SingletonDemo2(){}
        public static synchronized SingletonDemo2 getInstance(){
            if (instance == null) {
                instance = new SingletonDemo2();
            }
            return instance;
        }
    }
    

    3.显式的锁(Lock)

    import java.util.concurrent.locks.*;
    
    public class SingletonDemo2 {
        private static SingletonDemo2 instance;
        private SingletonDemo2(){}
        private static Lock lock = new ReentrantLock();
        public static SingletonDemo2 getInstance(){
            lock.lock();
            try{
                if (instance == null) {
                    instance = new SingletonDemo2();
                }
                return instance; 
            } finally {
                lock.unlock();
            }
        }
    }
    

    用synchronized不能尝试着获取锁且最终获取锁会失败,或尝试获取锁一段时间,然后放弃它时,应使用Lock锁:

    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.*;
    
    public class SingletonDemo2 {
        private static SingletonDemo2 instance;
        private SingletonDemo2(){}
        private static Lock lock = new ReentrantLock();
        public static SingletonDemo2 getInstance(){
            boolean captured = false;
            try {
                captured = lock.tryLock(2, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.lock();
            try{
                if (instance == null) {
                    instance = new SingletonDemo2();
                }
                return instance;
            } finally {
                if (captured){
                    lock.unlock();
                }
            }
        }
    }
    

    4.原子性

    原子性操作是不能被线程调度机制中断的操作。原子性可应用于除long 和 double 之外的所有基本数据类型,因jvm会将64位的long和double的读取和写入当做两个分离的32位操作,从而产生“字撕裂”。如果使用volatile关键字,可以使long和double 获得原子性。

    java 中仅基本数据类型(除long和double)的读取和赋值为院子操作。

    
    public class Atomicity {
      int i;
      void f1() { i++; }
      void f2() { i += 3; }
    } /* Output: (Sample)
    ...
    void f1();
      Code:
       0:        aload_0
       1:        dup
       2:        getfield        #2; //Field i:I
       5:        iconst_1
       6:        iadd
       7:        putfield        #2; //Field i:I
       10:        return
    
    void f2();
      Code:
       0:        aload_0
       1:        dup
       2:        getfield        #2; //Field i:I
       5:        iconst_3
       6:        iadd
       7:        putfield        #2; //Field i:I
       10:        return
    *///:~
    
    

    每条指令都会产生一个get和put,它们之间还有其他指令。

    5.原子类

    AtomicInteger

    AtomicLong

    AtomicReference

    6.临界区

    synchronized被用来指定某个对象,此对象的锁被用来对花括号内的代码进行同步控制:

    synchronized(syncObject){
         statements;
    }
    

    7.线程本地存储 (ThreadLocal)

    线程本地存储是一种自动化的机制,可以为使用相同变量的每个线程都创建不同的存储。

    //: ThreadLocalVariableHolder.java
    // Automatically giving each thread its own storage.
    import java.util.concurrent.*;
    import java.util.*;
    
    class Accessor implements Runnable {
      private final int id;
      public Accessor(int idn) { id = idn; }
      public void run() {
        while(!Thread.currentThread().isInterrupted()) {
          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 rand.nextInt(10000);
          }
        };
      public static void increment() {
        value.set(value.get() + 1);
      }
      public static int get() { return value.get(); }
      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.SECONDS.sleep(3);  // Run for a while
        exec.shutdownNow();         // All Accessors will quit
      }
    } /* Output: (Sample)
    #0: 9259
    #1: 556
    #2: 6694
    #3: 1862
    #4: 962
    #0: 9260
    #1: 557
    #2: 6695
    #3: 1863
    #4: 963
    ...
    *///:~
    

    8.在阻塞时终结(中断)

    线程状态:

    1. 新建
    2. 就绪
    3. 阻塞
    4. 死亡

    进入阻塞状态的原因:

    1. 调用sleep()使任务休眠
    2. 调用wait()使任务挂起
    3. 任务在等待某个输入/输出完成
    4. 任务在等锁

    中断任务可调用Thread.interrupted()或 调用executor的shutdownNow()方法,会发送一个interrupted()调用给他启动的所有线程。如果使用Executor的submit()来启动任务,就可以持有该任务的上下文。submit()将返回一个Future<?>,可以调用其cancel()来只中断某个特定的任务。

    其中仅sleep状态可中断。等待io和等待锁,都会使任务的中断失效:

    解决

    1.关闭任务在其上发生阻塞的底层资源。

    2.interrupt()可打断被互斥阻塞的调用

    相关文章

      网友评论

          本文标题:共享受限资源及锁

          本文链接:https://www.haomeiwen.com/subject/ymwymftx.html