java多线程与线程并发三:线程同步通信

本文章内容整理自:张孝祥_Java多线程与并发库高级应用视频教程。

有些时候,线程间需要传递消息,比如下面这道面试题:

子线程循环10次,然后主线程循环100次,然后又回到子线程循环50次,然后再回到主线程循环100次。以上过程一共循环50次。

通过分析可以知道,主线程和子线程是互斥的,即主线程和子线程不能同时执行。此外,主线程和子线程有固定的轮换关系,主线程执行完后,必须是子线程接着执行,然后又是主线程执行。

要达到这种效果,光是线程互斥是不够的。因为有可能主线程执行完之后,cpu又将执行的权利分配给主线程,这样主线程又会执行一遍。要让两个线程交替执行,就需要这两个线程间可以通信。主线程执行完了,就通知子线程执行。子线程执行完了,再通知主线程执行。如此往复。

像这种线程间协作的情况,就叫线程同步。

下面直接贴出代码

package com.sky.thread;

public class Test4 {
    private boolean mainOrSub = true;//线程间通信的变量
    public static void main(String[] args) {
        final Test4 t4 = new Test4();
        new Thread(new Runnable() {

            @Override
            public void run() {
                //执行50次主线程
                for (int i = 0; i < 50; i++) {
                    try {
                        t4.mainThread();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        new Thread(new Runnable() {

            @Override
            public void run() {
                //执行50次子线程
                for (int i = 0; i < 50; i++) {
                    try {
                        t4.subThread();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        }).start();
    }

    //主线程执行的方法
    public synchronized void mainThread() throws InterruptedException {
        //判断是否轮到自己执行
        //此处用while代替if,可以提高程序的健壮性。
        //线程有时会自己醒来,如果用if,当线程自己醒来后会接着执行this.wait()后面的代码,这样是不对的。
        //而使用while,线程自己醒来后,根据while的规则,会再判断一次mainOrSub的值。
        if (mainOrSub) {
            //如果mainOrSub是true,表示不该自己执行。于是把线程挂起。
            this.wait();
        }
        for (int i = 0; i < 100; i++) {
            System.out.println("main-"+Thread.currentThread().getName() + ":" + i);
        }
        //执行完毕后更改mainOrSub的状态,并唤醒其他线程
        mainOrSub = true;
        this.notify();
    }

    //子线程执行的方法
    public synchronized void subThread() throws InterruptedException {
        //判断是否轮到自己执行
        while (!mainOrSub) {
            //如果mainOrSub是false,表示不该自己执行。于是把线程挂起。
            this.wait();
        }
        for (int i = 0; i < 10; i++) {
            System.out.println("sub-"+Thread.currentThread().getName() + ":" + i);
        }
        //执行完毕后更改mainOrSub的状态,并唤醒其他线程
        mainOrSub = false;
        this.notify();
    }
}

在上面的代码中,创建了一个变量mainOrSub用于线程间通信。通过mainOrSub的值来控制线程的交替执行。

可见,使用多个线程都可以访问到的变量,就可以实现线程间通信。 

还有一点值得注意,在判断mainOrSub的值时,用while代替了if,这样可以提高程序的健壮性。因为使用wait()挂起的线程有时会自己醒来。如果用if,当线程自己醒来后会接着执行this.wait()后面的代码,而此时并不该它执行。如果用while,线程自己醒来后,根据while的规则,会再判断一次mainOrSub的值,这样就可以保证线程完全依照mainOrSub的值来决定要不要执行。

经验:要用到共同数据(包括同步锁)的若干个方法应该归在同一个类身上,这种设计体现了高内聚和程序的健壮性。

posted @ 2014-03-24 23:46  百里弈  阅读(540)  评论(0编辑  收藏  举报