Java核心知识点学习----使用Condition控制线程通信

一.需求

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

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

二.实现

1.分析

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

2.实现效果

Java核心知识点学习----使用Condition控制线程通信

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:[email protected]

 * @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:[email protected]

 * @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).官方提供的例子

做了简单的修改:

 

 先看效果:

Java核心知识点学习----使用Condition控制线程通信

再看代码:

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:[email protected]

* @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??

 

 

 

你可能感兴趣的:(Condition)