【多线程】三种方案实现多线程之间相互协作的通信

来源:互联网 发布:知乎周刊 编辑:程序博客网 时间:2024/05/22 04:34
在并发编程中,经常会遇到多个线程之间需要相互协作的情况,即并不是多个线程同时执行,而是按照一定的顺序循环执行的情况。那么怎样去实现这种效果呢?这里介绍三种方案。这里都以子线程循环10次,然后主线程循环10次,然后往复循环50次的思路来做例子。在下面的例子中flag代表一个共享变量。

一、synchronized+notify+wait+flag

public class communication01 {    public static void main(String[] args){        final besiness b=new besiness();        new Thread(new Runnable() {            @Override            public void run() {                for(int i=1;i<=50;i++){                    b.sub(i);                }            }        }).start();        for (int i = 1; i <= 50; i++) {            b.main(i);        }    }}    class besiness{        private static  boolean flag=true;//flag为true时允许main访问,为false时允许suB访问        public synchronized void main(int i){            while(!flag){                try {                    this.wait();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            for (int j = 1; j <= 10; j++) {                System.out.println("main thread==" + j + ",loop of " + i);            }            flag=false;            this.notify();        }        public  synchronized  void sub(int i){            while (flag){                try {                    this.wait();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            for (int j = 1; j <= 10; j++) {                System.out.println("sub thread==" + j + ",loop of " + i);            }            flag=true;            this.notify();        }    }
这种方案是通过对两个线程中分别要执行的方法加锁synchronized,保证每次执行main时不被sub打断,执行sub循环时,不被main打断。这里采用了对象object的notify和wait来实现线程之间的通信。当main方法执行完成后,让执行main方法的线程等待,等待sub方法执行完成后,通知(notify)main线程然后继续执行。这种方式有一个缺点,由于notify和wait使用的是Object的方法,所以不能单独的让某个特定的线程收到通知或者让他等待,而在存在多个线程同时等待时,只能通过notifyAll来通知所有的线程。不够灵活。

二、lock+condition+flag

 public static void main(String[] args){        final besiness b=new besiness();        new Thread(new Runnable() {            @Override            public void run() {                for(int i=1;i<=50;i++){                    b.sub2(i);                }            }        }).start();        new Thread(new Runnable() {            @Override            public void run() {                for(int i=1;i<=50;i++){                    b.sub3(i);                }            }        }).start();        for (int i = 1; i <= 50; i++) {            b.main(i);        }    }   static  class besiness{        private   int flag=1;//flag为true时允许main访问,为false时允许suB访问        //condition1来控制main和sub2之间的循环通信       Condition condition1=lock.newCondition() ;       //condition2来控制sub2和sub3之间的循环通信       Condition condition2=lock.newCondition() ;       //condition1来控制main和sub3之间的循环通信       Condition condition3=lock.newCondition() ;        public  void main(int i){            lock.lock();            try{                while(flag!=1){                    try {                        condition1.await();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                for (int j = 1; j <= 20; j++) {                    System.out.println("main thread==" + j + ",loop of " + i);                }                flag=2;                condition2.signal();            }finally {                lock.unlock();            }        }        public    void sub2(int i){            lock.lock();            try{                while ( flag !=2){                    try {                        condition2.await();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                for (int j = 1; j <= 20; j++) {                    System.out.println("sub2 thread==" + j + ",loop of " + i);                }                flag=3;                condition3.signal();            }finally {                lock.unlock();            }        }       public    void sub3(int i){           lock.lock();           try{               while ( flag !=3){                   try {                       condition3.await();                   } catch (InterruptedException e) {                       e.printStackTrace();                   }               }               for (int j = 1; j <= 20; j++) {                   System.out.println("sub3 thread==" + j + ",loop of " + i);               }               flag=1;               condition1.signal();           }finally {               lock.unlock();           }       }    }
这种方式是利用了Java5中提供的lock和condition,利用共享变量flag来实现线程之间的相互通信。同时在这个小例子中,相比上一个例子中增加了一个线程的循环。这是为了体现使用condition的优点。使用condition可以非常灵活的去控制线程与线程之间的通信。因为在一个类中可以创建多个condition的实例,我们可以通过condition不同的实例的signal和await方法来标识不同的两个线程之间相互通信的标识,而不是统一使用object的notify和wait方法了。同时利用lock方法可以利用锁的重入机制实现更加灵活的锁的应用。可以在需要的时候加锁或解锁。这样我们就可以实现多个线程之间的协调通信了。

三、semaphere+flag

    public static void main(String[] args){        final besiness b=new besiness();        new Thread(new Runnable() {            @Override            public void run() {                for(int i=1;i<=50;i++){                    b.sub(i);                }            }        }).start();        for (int i = 1; i <= 50; i++) {            b.main(i);        }    }   static class besiness{        private  int  flag=1;       final Semaphore sp=new Semaphore(1);//声明一个信号,共享一个资源,每次只能允许一个线程执行        public  void main(int i){            try {                sp.acquire();                while(flag!=1){                    sp.release();                }                for (int j = 1; j <= 10; j++) {                    System.out.println("main thread==" + j + ",loop of " + i);                }                flag=2;            } catch (InterruptedException e) {                e.printStackTrace();            }finally {                sp.release();            }        }        public   void sub(int i){            try{                try {                    sp.acquire();                } catch (InterruptedException e) {                    e.printStackTrace();                }                while (flag !=2){                    sp.release();                }                for (int j = 1; j <= 10; j++) {                    System.out.println("sub thread==" + j + ",loop of " + i);                }                flag=1;                sp.release();            }finally {                sp.release();            }        }    }
这里semaphere代表一个信号量,它可以指示共享资源的个数,也就是同时访问资源的线程个数。这里主要通过semaphere的acquire和release实现锁的功能从而实现线程之间的通信。利用semaphere不仅可以实现多个线程协调循环通信,在必要时还可以控制同一时间访问资源的个数。更加的灵活和方便。以上是实习多个线程之间相互协调通信的几种方案。
1 1
原创粉丝点击