Java 线程第三版 第四章 Thread Notification 读书笔记

一、等待与通知

public final void wait() throws InterruptedException

等待条件的发生。

public final void wait(long timeout) throws InterruptedException

等待条件的发生。如果通知没有在timeout指定的时间内发生,它还是会返回。

public final void wait(long timeout, int nanos) throws InterruptedException

等待条件的发生。如果通知没有在timeout指定的毫秒与纳秒内发生,它还是会返回。

public final void notify()

通知正在等待的Thread此条件已经发生。

public final void notifyAll()

通知所有正在等待的Thread此条件已经发生。

    等待-通知机制的目的为何?它是如何运作的? 

等待-通知机制是同步机制。它更是一个通信机制:它能够让某个Thread与其他Thread在特定条件符合时进行通信。等待-通知机制并没有指定特定条件是什么。

    等待-通知机制能够用来取代synchronized机制吗?

不行,wait、notify、notifyAll方法方法必须从synchronized方法块中调用,因为需要其确保等待与通知的线程安全不会出现竞态条件。

public class AnimatedCharacterDisplayCanvas extends CharacterDisplayCanvas implements CharacterListener, Runnable {

    private boolean done = true;
    private int curX = 0;
    private Thread timer = null;

    public AnimatedCharacterDisplayCanvas() {
    }

    public AnimatedCharacterDisplayCanvas(CharacterSource cs) {
        super(cs);
    }

    public synchronized void newCharacter(CharacterEvent ce) {
        curX = 0;
        tmpChar[0] = (char) ce.character;
        repaint();
    }

    protected synchronized void paintComponent(Graphics gc) {
        Dimension d = getSize();
        gc.clearRect(0, 0, d.width, d.height);
        if (tmpChar[0] == 0)
            return;
        int charWidth = fm.charWidth(tmpChar[0]);
        gc.drawChars(tmpChar, 0, 1,
                     curX++, fontHeight);
    }

    public synchronized void run() {
        while (true) {
            try {
                if (done) {
                    wait();
                } else {
                    repaint();
                    wait(100);
                }
            } catch (InterruptedException ie) {
                return;
            }
        }
    }

    public synchronized void setDone(boolean b) {
        done = b;

        if (timer == null) {
            timer = new Thread(this);
            timer.start();
        }
        if (!done)
            notify();
    }
 }

     sleep与wait方法的区别?

wait与notify方法都必须在同步方法中,在一个类中的两个同步方法使用的都是当前this作为锁,wait方法执行后会释放掉当前方法锁,因为如果不释放的话notify永远无法获取到此锁,也就永远无法执行notify。

sleep方法是不会释放锁的,并且阻塞当前线程,一直到sleep指定的时间结束。

等待-通知机制与同步

存在于等待-通知机制中的竞态条件细节是什么?

1. 第一个Thread测试条件并确认它需要等待

2. 第二个Thread设定此条件

3. 第二个Thread调用notify方法,这不会被收到,因为第二个Thread还没有进入等待

4. 第一个Thread调用wait方法

这个潜在的竞态条件状况是如何解决的? 

调用wait与调用notify的方法都使用同一锁(当前对象this),由锁来保证操作的原子性。

如果Thread收到通知,是否能够保证条件被正确的设定?

不是,描述情景

wait(), notify() 与 notifyAll()

当一个以上的Thread在等待通知时哪个Thread会在调用notify的时候收到通知?

Java规范没有定义哪一个Thread收到通知。但是Object class 提供另外一个方法notifyAll

是否noitfyAll方法真的唤醒所有的Thread?

是也不是。所有等待中Thread都会被唤醒,但它们都还没要重新取得对象的lock。所以这些Thread并不是并行地执行:它们都必须等待对象lock被释放掉。因此,一次只有一个Thread能够执行,且只有在调用notifyAll方法的这个Thread释放掉它的lock之后。

为什么要唤醒所有的Thread?

1. 有多个Thread处于等待状态,无法指定哪一个收到通知

2. 并不知道具体有多少个Thread处于等待,干脆同步通知,由等待中的Thread自己处理。

等待-通知机制与synchronized块

public class AnimatedCharacterDisplayCanvas extends CharacterDisplayCanvas implements CharacterListener, Runnable {

    private boolean done = true;
    private int curX = 0;
    private Thread timer = null;
    private Object doneLock = new Object();

    public AnimatedCharacterDisplayCanvas() {
    }

    public AnimatedCharacterDisplayCanvas(CharacterSource cs) {
        super(cs);
    }

    public synchronized void newCharacter(CharacterEvent ce) {
        curX = 0;
        tmpChar[0] = (char) ce.character;
        repaint();
    }

    protected synchronized void paintComponent(Graphics gc) {
        Dimension d = getSize();
        gc.clearRect(0, 0, d.width, d.height);
        if (tmpChar[0] == 0)
            return;
        int charWidth = fm.charWidth(tmpChar[0]);
        gc.drawChars(tmpChar, 0, 1,
                     curX++, fontHeight);
    }

    public void run() {
	synchronized(doneLock) {
            while (true) {
                try {
                    if (done) {
                        doneLock.wait();
                    } else {
                        repaint();
                        doneLock.wait(100);
                    }
                } catch (InterruptedException ie) {
                    return;
                }
            }
	}
    }

    public void setDone(boolean b) {
	synchronized(doneLock) {
            done = b;

            if (timer == null) {
                timer = new Thread(this);
                timer.start();
            }
            if (!done)
                doneLock.notify();
	}
    }
 }

二、条件变量

POSIX条件变量的四个基本函数:wait(), thimeed_wait(), signal, broadcast。直接对应Java提供的wait(), wait(long),notify(),notifyAll

J2SE 5.0加入提供条件变量功能的类。此类食欲Lock interface并用。因为这个新的interface是与调用以及lock对象分开的,它在使用方法上的灵活性就如筒其他Threading系统中的条件变量一样。

public class RandomCharacterGenerator extends Thread implements CharacterSource {
    private static char[] chars;
    private static String charArray = "abcdefghijklmnopqrstuvwxyz0123456789";
    static {
        chars = charArray.toCharArray();
    }

    private Random random;
    private CharacterEventHandler handler;
    private boolean done = true;
    private Lock lock = new ReentrantLock();
    private Condition cv = lock.newCondition();

    public RandomCharacterGenerator() {
        random = new Random();
        handler = new CharacterEventHandler();
    }

    public int getPauseTime() {
        return (int) (Math.max(1000, 5000 * random.nextDouble()));
    }

    public void addCharacterListener(CharacterListener cl) {
        handler.addCharacterListener(cl);
    }

    public void removeCharacterListener(CharacterListener cl) {
        handler.removeCharacterListener(cl);
    }

    public void nextCharacter() {
        handler.fireNewCharacter(this,
                                (int) chars[random.nextInt(chars.length)]);
    }

    public void run() {
        try {
            lock.lock();
            while (true) {
                try {
                    if (done) {
                        cv.await();
                    } else {
                        nextCharacter();
                        cv.await(getPauseTime(), TimeUnit.MILLISECONDS);
                    }
                } catch (InterruptedException ie) {
                    return;
                }
            }
        } finally {
            lock.unlock();
        }
    }

    public void setDone(boolean b) {
        try {
            lock.lock();
            done = b;

            if (!done) cv.signal();
        } finally {
            lock.unlock();
        }
    }
}

     为什么使用Condition而不使用wait与notify?或者说是二者的区别?

1. Condition与wait相同都是因为需要确保同步安全(即避免竞态条件)而必须使用锁机制保证。

2. Lock对象不能与wait、notify方法搭配,因为这些方法已经在内部被用来实现Lock对象,持有lock对象并不表示持有了该对象的同步锁。

3. Condition对象不像等待-通知机制,它是被创建不同的对象。对每一个Lock对象都可以创建一个以上的Condition对象,这表示我们可以针对个别的Thread或ThreadGroup进行独立的设定。

Condition方法:

void await()

等待条件的发生。

void awaitUniterruptibly()

等待条件的发生。与await()不同,它的调用不可能被中断。

void signal()

通知某个等待使用Condition对象的Thread此条件已经发生。

void signalAll()

通知所有等待使用Condition对象的Thread此条件已经发生。

Java 线程第三版 第四章 Thread Notification 读书笔记,布布扣,bubuko.com

时间: 2024-10-07 16:07:57

Java 线程第三版 第四章 Thread Notification 读书笔记的相关文章

Java 线程第三版 第六章 高级同步议题 读书笔记

多线程数据同步错误比较难检测,因为通常是与事件的特定发生顺序有关. 一.同步术语 Barrier(屏障) barrier是多个Thread的集合点:所有的Thread都应该到齐在这个barrier之后才能允许它们继续下去. Condition variable(条件变量) 实际上不是变量,而是与某个lock有关联的变量. Event variable(事件变量) 条件变量的另一个名称. Critical section(临界区) 临界区是synchronized方法或者block. Lock(锁

Java 线程第三版 第五章 极简同步技巧 读书笔记

一.能避免同步吗? 取得锁会因为以下原因导致成本很高: 取得由竞争的锁需要在虚拟机的层面上运行更多的程序代码. 要取得有竞争锁的线程总是必须等到锁被释放后. 1. 寄存器的效应 计算机有一定数量的主寄存器用来存储与程序有关的数据. 从逻辑上的观点来看,每个Thread都有自己的一组寄存器.当操作系统将某个Thread分配给CPU时,它会把该Thread特有的信息加载到CPU的寄存器中.在分配不同的Thread给CPU之前,它会将寄存器的信息存下来.所以Thread间绝不会共享保存在寄存器的数据.

Java 线程第三版 第一章Thread导论、 第二章Thread的创建与管理读书笔记

第一章 Thread导论 为何要用Thread ? 非阻塞I/O I/O多路技术 轮询(polling) 信号 警告(Alarm)和定时器(Timer) 独立的任务(Task) 并行算法 第二章 Thread的创建与管理 一.什么是Thread ? Thread是所在主机执行的应用程序任务(task). 只有一个线程的例子: public class Factorial { public static void main(String[] args) { int n = 5; System.ou

Java 线程第三版 第三章数据同步 读书笔记

多线程间共享数据问题 一.Synchronized关键字 atomic一词与"原子"无关,它曾经被认为是物质的最小的单元,不能再被拆解成更小的部分. 当一个方法被声明成synchronized,要执行此方法的thread必须先取得一个token,我们将它称为锁.一旦该方法取得(或者说是获得)锁,它将运行此方法然后释放掉(或者返回)此锁.不管方法时怎样返回的(包括通过异常)该锁会被释放. 二.Volatile关键字 如果变量被标示为volatile,每次使用该变量时都必须从主寄存器中读出

Java 线程第三版 第九章 Thread调度 读书笔记

一.Thread调度的概述 import java.util.*; import java.text.*; public class Task implements Runnable { long n; String id; private long fib(long n) { if (n == 0) return 0L; if (n == 1) return 1L; return fib(n - 1) + fib(n - 2); } public Task(long n, String id)

Java 线程第三版 第八章 Thread与Collection Class 读书笔记

JDK1.2引入最有争议性的改变是将集合类默认为不是Thread安全性的. 一.Collection Class的概述 1. 具有Threadsafe 的Collection Class: java.util.Vector(List) 列表集合,通过索引操作. java.util.Stack(List) 继承自Vector,提供LIFO的顺序操作push进入,pop出元素. java.util.Hashtable(Map) 一个简单.无序的key与value的映射. java.util.conc

《Java并发编程实战》第六章 任务运行 读书笔记

一. 在线程中运行任务 无限制创建线程的不足 .线程生命周期的开销很高 .资源消耗 .稳定性 二.Executor框架 Executor基于生产者-消费者模式,提交任务的操作相当于生产者.运行任务的线程则相当于消费者. 1. Executors 返回 ExecutorService 2. ExecutorService方法submit.execute 3. ExecutorService.submit 返回 Future 线程池,Executors方法介绍 方法名 解释 newFixedThre

《Java并发编程实战》第五章 同步容器类 读书笔记

一.同步容器类 1. 同步容器类的问题 线程容器类都是线程安全的.可是当在其上进行符合操作则须要而外加锁保护其安全性. 常见符合操作包括: . 迭代 . 跳转(依据指定顺序找到当前元素的下一个元素) . 条件运算 迭代问题能够查看之前的文章 <Java ConcurrentModificationException 异常分析与解决方式> 二.并发容器 集合类型 非线程安全 线程安全 List ArrayList CopyOnWriteArrayList Set SortedSet Concur

Javascript模式(第四章函数)------读书笔记

一 背景 js函数的两个特点:1 函数是第一类对象(first-class object):2 函数可以提供作用域 1 函数是对象: 1 函数可以在运行时动态创建,还可以在程序执行过程中创建 2 可以被赋值给变量,还可以被删除 3 可以作为参数传递给别的函数,可以作为返回值,被别的函数返回, 4 可以拥有自己的属性和方法 2 由于JS没有块级作用域的概念,因此在涉及到控制变量作用域的时候,函数是必不可少的工具 1.1 消除术语歧义:我们来看一下命名函数表达式.你们函数表达式以及函数声明的定义 1