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

在并发编程中,经常会遇到多个线程之间需要相互协作的情况,即并不是多个线程同时执行,而是按照一定的顺序循环执行的情况。
那么怎样去实现这种效果呢?这里介绍三种方案。
这里都以子线程循环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不仅可以实现多个线程协调循环通信,在必要时还可以控制同一时间访问资源的个数。更加的灵活和方便。

四、countdownLatch

package com.jihite;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CountDownLatchTest {
    private static final int RUNNER_COUNT = 10;
    public static void main(String[] args) throws InterruptedException {
        final CountDownLatch begin = new CountDownLatch(1);
        final CountDownLatch end = new CountDownLatch(RUNNER_COUNT);
        final ExecutorService exec = Executors.newFixedThreadPool(10);

        for (int i = 0; i < RUNNER_COUNT; i++) {
            final int NO = i + 1;
            Runnable run = new Runnable() {
                @Override
                public void run() {
                    try {
                        begin.await();
                        Thread.sleep((long)(Math.random() * 10000));
                        System.out.println("No." + NO + " arrived");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        end.countDown();
                    }
                }
            };
            exec.submit(run);
        }

        System.out.println("Game Start ...");
        begin.countDown();
        end.await();
//        end.await(30, TimeUnit.SECONDS);
        System.out.println("Game Over.");

        exec.shutdown();
    }
}
以上是实习多个线程之间相互协调通信的几种方案。
  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值