zoukankan      html  css  js  c++  java
  • 常用多线程方法

    可重入锁

    ​ ReentrantLock类、synchronized关键字,属于悲观锁。

    ​ 可重入锁,即递归锁。指在同一线程内,外层函数获得锁之后,内层递归函数仍然可以获得该锁。

    ​ 作用:防止在同一线程中多次获取锁而导致死锁发生。

    自旋锁

    ​ java.util.concurrent.atomic包下的AtomicReference等原子类的使用,属于乐观锁。

    ​ 当一个线程在获取锁的时候,如果锁已经被其他线程获取,那么该线程将循环等待,然后不断的判断,锁是否能够被成功获取,直到获得锁才会退出循环。

    ​ 获取锁的线程一直处于活动状态,但是并没有执行任何有效的任务,使用这种锁会造成busy-waiting。所以需要增加一些退出忙等的方法。

    ​ 实现:CAS。

    ​ 缺点:CPU可能长时间极高,不释放线程,不公平造成其他“线程饥饿”问题。CAS操作可能存在ABA的问题,就是说:假如一个值原来是A,变成了B,又变成了A,那么CAS检查时会发现它的值没有发生变化,但是实际上却变化了,如果线程不关心变量中途如何变化,那么这个不是什么问题;如果有些操作会依赖于对象的变化过程,此时的解决思路一般就是使用版本号,在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A - 2B - 3A。
    ​ 例如:原子引用,以无锁方式访问共享资源

    public class AtomicRefTest {
        public static void main(String[] args) throws InterruptedException {
            AtomicReference<Integer> atomRef = new AtomicReference<>(new Integer(1000));
    
            List<Thread> list = new ArrayList<>();
            for (int i = 0; i < 1000; i++) {
                Thread thread = new Thread(new Task(atomRef), "Thread-" + i);
                list.add(thread);
                thread.start();
            }
    
            for (Thread thread : list) {
                thread.join();
            }
    
            System.out.println(atomRef.get());    // 打印2000
        }
    
    }
    
    class Task implements Runnable {
        private AtomicReference<Integer> atomRef;
    
        Task(AtomicReference<Integer> atomRef) {
            this.atomRef = atomRef;
        }
    
        @Override
        public void run() {
            while (true) {    //自旋操作
                Integer oldV = atomRef.get();
                if (atomRef.compareAndSet(oldV, oldV + 1))  // CAS操作
                    break;
            }
        }
    }
    

    上述示例,最终打印“2000”。

    ​ 该示例并没有使用锁,而是使用自旋+CAS的无锁操作保证共享变量的线程安全。1000个线程,每个线程对金额增加1,最终结果为2000,如果线程不安全,最终结果应该会小于2000。

    ​ 总结:使用CAS的套路:

    AtomicReference<Object> atomRef = new AtomicReference<>(new Object());
    Object oldCache = atomRef.get();
    
    // 对缓存oldCache做一些操作
    Object newCache  =  someFunctionOfOld(oldCache); 
    
    // 如果期间没有其它线程改变了缓存值,则更新
    boolean success = atomRef.compareAndSet(oldCache , newCache);
    
  • 相关阅读:
    python socket练习
    python异常处理
    python类的反射
    类的特殊成员方法
    staticmethod classmethod property方法
    类的多态
    类的析构、继承
    python subprocess模块
    python面向对象
    discuz 使模板中的函数不解析 正常使用
  • 原文地址:https://www.cnblogs.com/aric2016/p/11494176.html
Copyright © 2011-2022 走看看