Java并发系列(十)之线程协作

19人阅读 评论(0) 收藏 举报
分类:

概要

  • 当多个线程可以一起工作去解决某个问题时,如果某些部分必须在其它部分之前完成,那么就需要对线程进行协调。

join()

  • 在线程中调用另一个线程的 join() 方法,会将当前线程挂起,而不是忙等待,直到目标线程结束。
  • 对于以下代码,虽然 b 线程先启动,但是因为在 b 线程中调用了 a 线程的 join() 方法,因此 b 线程会等待 a 线程结束才继续执行,因此最后能够保证 a 线程的输出先与 b 线程的输出。
public class JoinExample {

    private class A extends Thread {
        @Override
        public void run() {
            System.out.println("A");
        }
    }

    private class B extends Thread {

        private A a;

        B(A a) {
            this.a = a;
        }

        @Override
        public void run() {
            try {
                a.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("B");
        }
    }

    public void test() {
        A a = new A();
        B b = new B(a);
        b.start();
        a.start();
    }

    public static void main(String[] args) {
        JoinExample example = new JoinExample();
        example.test();
    }
}
  • 输出
A
B

wait() notify() notifyAll()

  • 调用 wait() 使得线程等待某个条件满足,线程在等待时会被挂起,当其他线程的运行使得这个条件满足时,其它线程会调用 notify()或者 notifyAll() 来唤醒挂起的线程。
  • 它们都属于 Object 的一部分,而不属于 Thread。
  • 只能用在同步方法或者同步控制块中使用,否则会在运行时抛出 IllegalMonitorStateExeception。
  • 使用 wait() 挂起期间,线程会释放锁。这是因为,如果没有释放锁,那么其它线程就无法进入对象的同步方法或者同步控制块中,那么就无法执行notify() 或者 notifyAll() 来唤醒挂起的线程,造成死锁。
public class WaitNotifyExample {
    public synchronized void before() {
        System.out.println("before");
        notifyAll();
    }

    public synchronized void after() {
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("after");
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        WaitNotifyExample example = new WaitNotifyExample();
        executorService.execute(() -> example.after());
        executorService.execute(() -> example.before());
    }
}

输出

before
after

wait() 和 sleep() 的区别

  • 1.wait() 是 Object 的方法,而 sleep() 是 Thread 的静态方法;
  • 2.wait() 会释放锁,sleep() 不会。

await() signal() signalAll()

  • java.util.concurrent 类库中提供了 Condition 类来实现线程之间的协调,可以在 Condition 上调用await() 方法使线程等待,其它线程调用 signal() 或 signalAll() 方法唤醒等待的线程。相比于 wait()这种等待方式,await() 可以指定等待的条件,因此更加灵活。
  • 使用 Lock 来获取一个 Condition 对象。

public class AwaitSignalExample {
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void before() {
        lock.lock();
        try {
            System.out.println("before");
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public void after() {
        lock.lock();
        try {
            condition.await();
            System.out.println("after");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
  public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        AwaitSignalExample example = new AwaitSignalExample();
        executorService.execute(() -> example.after());
        executorService.execute(() -> example.before());
    }
}

输出

before
after
查看评论

线程之间的协作

在Java中,线程协作通常通过wait()和notify(),notifyAll()三种方法来协作,调用wait()时会释放锁,而sleep并不会释放锁,故在线程协作之间,通常是用wait()让该线程...
  • xuguoli_beyondboy
  • xuguoli_beyondboy
  • 2015-07-15 23:44:12
  • 435

Java并发之线程之间协作

线程之间的协作1.wait()和notify()、notifyAll()方法(这些方法均属于基类Object)wait()函数的调用使当前线程A被阻塞以等待某个外部条件的发生(这个外部条件超出了当前方...
  • u010853261
  • u010853261
  • 2016-12-28 00:16:35
  • 790

Java 并发:线程间通信与协作

线程与线程之间不是相互独立的个体,它们彼此之间需要相互通信和协作,最典型的例子就是生产者-消费者问题。本文首先介绍 wait/notify 机制,并对实现该机制的两种方式——synchronized+...
  • justloveyou_
  • justloveyou_
  • 2017-02-08 17:43:18
  • 4105

JAVA线程间协作:Condition

内置条件队列存在一些缺陷。每个内置锁都只能有一个相关联的条件队列,因而在像BounderBuffer这种类中,多个线程可能在同一个条件队列上等待不同的条件谓词,并且在最常见的加锁模式下公开条件队列对象...
  • u013256816
  • u013256816
  • 2016-01-01 16:30:54
  • 4835

D - 小鑫の日常系列故事(十)——排名次

小鑫の日常系列故事(十)——排名次Time Limit: 1000 ms Memory Limit: 65536 KiBSubmit StatisticProblem Description小鑫在来到...
  • Allinone99
  • Allinone99
  • 2018-03-15 19:21:02
  • 59

小鑫の日常系列故事(十)——排名次

小鑫の日常系列故事(十)——排名次 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Descr...
  • Lycodeboy
  • Lycodeboy
  • 2016-11-07 00:44:26
  • 895

java学习之浅谈多线程3--线程间协作

通过保证临界区上多个线程的相互排斥,线程同步完全可以避免竞争状态的发生,但是有时还需要线程之间的协作。有两种方式可用于线程间的通信。 1.使用条件Condition Condition接口:+aw...
  • david_csu
  • david_csu
  • 2015-10-21 12:36:10
  • 190

小鑫の日常系列故事(十)——排名次 (sdut oj)

小鑫の日常系列故事(十)——排名次 Time Limit: 1000MS Memory Limit: 65536KB Problem Description ...
  • SwordsMan98
  • SwordsMan98
  • 2017-02-08 22:24:12
  • 395

小鑫去爬山

题目描述马上就要放假了,小鑫打算去爬山。 小鑫要去爬的这座山有n个海拔区间。为了清楚描述我们可以从上到下标号1到n。第i个区间有i个落脚点,每一个落脚点都有一个危险值。小鑫需要在第n个海拔区间挑选一...
  • OJZFY
  • OJZFY
  • 2015-12-04 17:34:43
  • 308

Java学习の路

System.out.println(Y    + 字符串连接符   int A = Integer.parseInt(args[0]);   double F = Double.parseDo...
  • OoChellyoO
  • OoChellyoO
  • 2016-10-13 21:13:39
  • 140
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 1万+
    积分: 1793
    排名: 2万+
    博客专栏
    最新评论