美文网首页
七周七并发读书笔记 第二章 线程与锁

七周七并发读书笔记 第二章 线程与锁

作者: williamlee | 来源:发表于2018-05-16 19:42 被阅读0次

第二章 线程与锁

2.1 简单粗暴

线程与锁模型是对底层硬件运行过程的形式化,该模型非常简单,但是使得程序容易出错并且难以维护。

2.2 第一天:互斥和内存模型

互斥--用锁保证某一时间仅有一个线程可以访问数据。带来竞态条件和死锁等问题。

竞态条件:代码行为取决于各操作的顺序。

看下面例子,猜测下输出内容:

public class Puzzle {

    static boolean answerReady = false;
    static int answer = 0;
    static Thread t1 = new Thread(() -> {
        answer = 42;
        answerReady = true;
    });

    static Thread t2 = new Thread(() -> {
        if (answerReady) {
            System.out.println("the meaning of life is:" + answer);
        } else {
            System.out.println("I don't know the answer");
        }
    });

    public static void main(String[] args) throws InterruptedException {
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }

}
  1. The meaning of life is 42
  2. I don't know the answer
  3. The meaning of life is 0

以上三种都可能,因为可能颠倒顺序:

  • 编译器的静态优化可以打乱代码的执行顺序
  • JVM的动态优化也会打乱代码的执行顺序
  • 硬件可以通过乱序执行来优化其性能

2.3 第二天 超越内置锁

内置锁虽然方便但是限制很多:

  • 一个线程因为等待内置锁而进入阻塞之后,就无法中断该线程了
  • 尝试获取内置锁时,无法设置超时
  • 获得内置锁,必须使用synchronized块

可中断锁:ReentrantLock.lockInterruptibly()

超时:ReentrantLock.tryLock(100, TimeUnit)

交替锁:链表中插入元素,不锁整个链表

public class ConcurrentSortList {

    private final Node head;
    private final Node tail;

    public ConcurrentSortList() {
        this.head = new Node();
        this.tail = new Node();
        head.next = tail;
        tail.prev = head;
    }

    public void insert(int value) {
        Node current = head;
        current.lock.lock();
        Node next = current.next;
        try {
            while (true) {
                next.lock.lock();
                try {
                    if (next == tail || next.value > value) {
                        Node node = new Node(value, current, next);
                        next.prev = node;
                        current.next = node;
                        return;
                    }
                } finally {
                    current.lock.unlock();
                }
                current = next;
                next = current.next;
            }
        } finally {
            next.lock.unlock();
        }
    }

    private class Node {
        int value;
        Node prev;
        Node next;
        ReentrantLock lock = new ReentrantLock();

        Node() {
        }

        Node(int value, Node prev, Node next) {
            this.value = value;
            this.prev = prev;
            this.next = next;
        }
    }
}

条件变量:等待某个事件发生

原子变量:无锁非阻塞算法的基础,这种算法可以不用锁和阻塞来达到同步的目的。

volatile变量:是一种低级形式的同步,并不能解决原子性的问题,随着JVM被不断优化,其提供了一些低开销的锁,volatile变量的适用场景也越来越少。

2.4 第三天:站在巨人的肩膀上

线程池

写时复制:保护性复制策略,在列表被修改时复制,已经投入使用的迭代器会使用当时的旧副本。

相关文章

网友评论

      本文标题:七周七并发读书笔记 第二章 线程与锁

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