Skip to article frontmatterSkip to article content

OOP中的并发操作也大量的使用到了lockcondition variable, 使用上和共享内存模型一脉相承.

OOP并发模型的新特性

并发OOP中也存在特殊概念, 适用于对象系统的并发操作, 这个概念叫做monitor.

Monitor是一种类, 其对象内部内置一个lock和至少一个condition variable. 它不仅提供互斥访问的机制, 还支持让访问该对象的线程休眠或被唤醒的功能, 从而有效管理并发环境下的同步与通信. 换句话说, monitor把lock和condition variable整合到了同一个对象中, 并使其更方便使用.

object作为monitor
显式使用this作为monitor
隐式使用this作为monitor

这里以java为例.

java中提供了synchronized关键词, 配合monitor使用达到lock/unlock的目的. 在临界区中, 我们还可以使用monitor.wait()和monitor.notify()方法对线程进行休眠和唤醒.

objectAsMonitor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class MonitorExample {
    // 构造一个object对象作为monitor
    private final Object monitor = new Object();
    private boolean ready = false;

    public void awaitCondition() throws InterruptedException {
        // 使用synchronized关键词, 使得这一段代码只能被互斥访问.
        synchronized (monitor) {
            while (!ready) {
                // monitor作为condition variable使用
                monitor.wait();
            }
        }
    }

    public void signalCondition() {
        synchronized (monitor) {
            ready = true;
            // monitor作为condition variable使用
            monitor.notify();
        }
    }

    public void synchronizedAccess() {
        synchronized (monitor) {
            System.out.println("Accessing shared resource safely.");
        }
    }
}

创造一个独立的object对象作为monitor使用.

monitor比起lock和condition variable, 提供了更简单, 更适合对象使用的api.

但缺点也很明显, 它为了使用方便, 牺牲了灵活性, 它的控制粒度比较粗, 在性能敏感的场景可能达不到性能要求.

基于这些特性, 当我们只需要简单粗粒度的互斥访问对象时, 可以采用monitor.

Monitor的实践

monitor的实践, 主要注意写法上不要出错.

遗漏synchronize
Alien method
dirtyRead.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class DirtyRead {
    private int data = 0;

    // 写方法置为synchronized
    public synchronized void write(int value) {
        System.out.println("Writing value: " + value);
        try {
            Thread.sleep(100); // Simulate delay during write
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        data = value;
        System.out.println("Value written: " + value);
    }

    // 忘记把读方法置为synchronized, 这会导致读到脏数据
    public int read() {
        System.out.println("Reading value: " + data);
        return data;
    }
}

对临界区数据的所有读写操作都应该是synchronized