Hi_Amos
坚持每天都在进步!!

一.需求

实现线程间的通信,主线程循环3次后,子线程2循环2次,子线程3循环3次,然后主线程接着循环3次,如此循环3次.

即:A->B->C---A->B->C---A->B->C

二.实现

1.分析

在前面文章java核心知识点学习----多线程并发之线程间的通信,notify,wait,曾实现过需求两个线程间隔循环的例子.涉及到3个线程就使用之间的方法就有点麻烦了,这里借着刚学的Lock锁可以很方便实现互斥,但如何实现三个线程间的通信呢?

2.实现效果

3.实现代码

package com.amos.concurrent;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @ClassName: ThreadSynchronizedConnect
 * @Description:实现线程间的通信,需求:主线程循环3次后,子线程2循环2次,子线程3循环3次,然后主线程接着循环3次,如此循环3次.A->B->C---A->B->C---A->B->C
 * @author: amosli
 * @email:hi_amos@outlook.com
 * @date Apr 20, 2014 4:39:44 PM
 */
public class ThreeConnect {

    public static void main(String[] args) {
        final Business business = new Business();
        new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 3; i++) {
                    business.sub2(i);
                }
            }
        }).start();

        new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 3; i++) {
                    business.sub3(i);
                }
            }
        }).start();

        for (int i = 0; i < 3; i++) {
            business.main(i);
        }
    }

    static class Business {
        Lock lock = new ReentrantLock();
        Condition conditionmain = lock.newCondition();
        Condition conditionsub2 = lock.newCondition();
        Condition conditionsub3 = lock.newCondition();

        private int current = 1;

        // 子方法2
        public void sub2(int i) {
            lock.lock();
            try {
                if (current != 2) {// 如果不为true,将等待,Blocked状态
                    try {
                        conditionsub2.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                for (int j = 0; j < 2; j++) {
                    System.out.println("sub2 thread:" + j + "  loop:" + i);
                }
                current = 3;
                conditionsub3.signal();// 唤醒3
            } finally {
                lock.unlock();
            }
        }

        // 子方法3
        public void sub3(int i) {
            lock.lock();
            try {
                if (current != 3) {// 如果不为true,将等待,Blocked状态
                    try {
                        conditionsub3.await();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                for (int j = 0; j < 2; j++) {
                    System.out.println("sub3 thread:" + j + "  loop:" + i);
                }
                current = 1;
                conditionmain.signal();
            } finally {
                lock.unlock();
            }
        }

        // 主方法
        public void main(int i) {
            lock.lock();
            try {
                if (current != 1) {
                    try {
                        conditionmain.await();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                for (int j = 0; j < 3; j++) {
                    System.out.println("main thread:" + j + "  loop:" + i);
                }
                current = 2;
                conditionsub2.signal();
            } finally {
                lock.unlock();
            }

        }

    }

}

4.代码说明

上面的代码中用的是Lock进行加锁操作的,然后线程间的通信没有用之前的wait(),notify()方法用的是Conditon的await()和signal()

为什么要使用Condition??

如果程序中不使用synchronized关键字来保证同步,而是使用Lock对象来保证数据同步,则系统中不存在隐式的同步监视器,也就不能使用wait().notify()方法进行线程通信了.

因为使用了Lock对象,所以要使线程间通信,可以使用Condition进行控制线程间通信.

Condition将同步监视器方法(wait(),notify(),notifyall()等)分解成截然不同的对象,以便通过将这些对象与Lock对象组合使用,为每个对象提供多个等待集(wait-set).

创建一个Condition,只需要lock.newCondition()即可,lock是已经new 好的ReentrantLock()对象.

>>await()方法与wait()功能类似,都是将线程加入到阻塞状态.

>>signal()方法与notify()方法类似,都是唤醒等待中的线程,只是signal()方法可以指定具体要唤醒的线程.

>>signalAll()方法与notifyAll()方法类似,都是唤醒所有等待中的线程.

 

5.扩展

1).下面是简单的对比,notify和signal等方法的对比,其效果是完全一样的.

package com.amos.concurrent;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @ClassName: ConditionConnect
 * @Description:用condition替代wait,notify实现线程间的通信,需求:子线程循环10次,主线程循环100次,这样间隔循环50次.
 * @author: amosli
 * @email:hi_amos@outlook.com
 * @date Apr 24, 2014 12:07:23 AM
 */
public class ConditionConnect {

    public static void main(String[] args) {
        final Business business = new Business();
        new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 5; i++) {
                    business.sub(i);
                }
            }
        }).start();

        for (int i = 0; i < 5; i++) {
            business.main(i);
        }
    }

    /*
     * 经验:要用到共同数据(包括同步锁)的若干方法,应该归在同一个类身上,这样方便实现,高类聚和程序的健状性上.
     */
    static class Business {
        private boolean is_sub = true;
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();

        // 子方法
        public void sub(int i) {
            lock.lock();
            try {
                while (!is_sub) {// 如果不为true,将等待,Blocked状态
                    try {
                        // this.wait();
                        condition.await();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                for (int j = 0; j < 2; j++) {
                    System.out.println("sub thread:" + j + "  loop:" + i);
                }
                is_sub = false;
                // this.notify();//唤醒正在等待的线程
                condition.signal();
            } finally {
                lock.unlock();
            }

        }

        // 主方法
        public void main(int i) {
            lock.lock();
            try {
                while (is_sub) {
                    try {
                        // this.wait();
                        condition.await();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                for (int j = 0; j < 10; j++) {
                    System.out.println("main thread:" + j + "  loop:" + i);
                }
                is_sub = true;
                // this.notify();
                condition.signal();
            } finally {
                lock.unlock();
            }

        }
    }

}

 

2).官方提供的例子

做了简单的修改:

 

 先看效果:

再看代码:

package com.amos.concurrent;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/** 
* @ClassName: ConditionTest 
* @Description: 官方提供的例子
* @author: amosli
* @email:hi_amos@outlook.com
* @date Apr 24, 2014 12:40:58 AM  
*/
public class ConditionTest {
    public static void main(String[] args) throws Exception {
        BoundedBuffer buffer = new BoundedBuffer();
        buffer.put("hi_amos");
        for(int i=0;i<3;i++){
            buffer.put(i);
            System.out.println("take:"+buffer.take());
        }
        
    }
    static  class BoundedBuffer {
           final Lock lock = new ReentrantLock();
           final Condition notFull  = lock.newCondition(); 
           final Condition notEmpty = lock.newCondition(); 

           final Object[] items = new Object[100];
           int putptr, takeptr, count;
           
           //设值
           public void put(Object x) throws InterruptedException {
             lock.lock();
             try {
               while (count == items.length)
                 notFull.await();
               items[putptr] = x;
               if (++putptr == items.length) putptr = 0;
               ++count;
               notEmpty.signal();
             } finally {
               lock.unlock();
             }
           }

           //取值
           public Object take() throws InterruptedException {
             lock.lock();
             try {
               while (count == 0)
                 notEmpty.await();
               Object x = items[takeptr];
               if (++takeptr == items.length) takeptr = 0;
               --count;
               notFull.signal();
               return x;
             } finally {
               lock.unlock();
             }
           }
         }
}

 

思考:例子中为什么要new 2个condition??

 

 

 

posted on 2014-04-24 01:56  Hi_Amos  阅读(590)  评论(0编辑  收藏  举报