Java并发编程 之 阻塞队列和CountDownLatch

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/MakeContral/article/details/78122769

前几天看到一个面试题目:有一个长度为2000的字符串,开三个线程去判断字符串中”u51”的个数。

当时看到这个题目的时候,对并发编程是没有什么经验的,在实际项目多线程的应用也只有一两次。最近在恶补《Java并发编程的艺术》,对这个题目就有了解题的思路了。在这里记录一下对该题的解法和思路。

一开始的时候,我能确定的是对“u51”个数相加是需要做同步处理,主要是如何去用三个线程去遍历这个字符串呢。需要保证索引index每个线程只能拿到一个。所以我这里引用了阻塞队列。这样每个线程去take的时候保持每个index是唯一的。

因为最近才去看多线程编程,如果有错误的地方,希望路过的大虾能给指出。

先对阻塞队列ArrayBlockingQueue一些方法进行说明

这里写图片描述

CountDownLatch 不需要多说,初始设定一个值,每次调用countDown会导致值减一。countDownLatch.await()一直等待该值变为0才继续执行。

import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;

/**
 * Created by JinTX on 2017/9/28.
 */
public class ThreadTest extends Thread{

    static String str;//记录字符串
    static int strLength = 0;//记录字符串的长度
    static int count = 0;//记录匹配成功字符串的个数,即"u51"的个数
    static ArrayBlockingQueue<Object> stringNumber = new ArrayBlockingQueue<Object>(10000);//用阻塞队列来放字符串的下标

    /*需要做同步处理,因为这里的count++并不是一个原子操作*/
    public static synchronized void countAdd(){
        count++;
    }

    /*匹配字符的方法*/
    public static boolean isStrFind(char a,char b,char c){
        if(a=='u' && b=='5' && c=='1'){
            return true;
        }else{
            return false;
        }
    }

    public static class MyRunnable implements Runnable{

        CountDownLatch countDownLatch;

        public MyRunnable(CountDownLatch countDownLatch){
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            try {
            /*这里我用的是poll,主要是因为take是阻塞的。即如果队列中没有
            下标可以拿的时候,就会一直等待。而用poll是不会阻塞的。
            会在拿不到的时候会返回null*/
                Integer x = (Integer) stringNumber.poll();
                if(x!=null) {
                /*需要先判断x是不是null,不然为null执行x<strLength会报空指针*/
                    while (x!=null && x < strLength) {
                        if (x + 2 < strLength) {
                            char a = str.charAt(x);
                            char b = str.charAt(x + 1);
                            char c = str.charAt(x + 2);
                            /*一开始我用indexOF去判断但是结果一直是错的,
                            所以自己定义了一个方法*/
                            if (isStrFind(a, b, c)) {
                                countAdd();
                               System.out.println(Thread.currentThread() + ":" + x);
                            }
                        }
                        x = (Integer) stringNumber.poll(); 
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
            /*运行结束,把计数器的个数减一**/
                countDownLatch.countDown();
            }
        }

    }


    public static void main(String[] args) throws Exception{
        Scanner scanner = new Scanner(System.in);
        while(scanner.hasNext()){
            str = scanner.next();
            strLength = str.length();

            for(int i=0;i<strLength;i++){
                stringNumber.put(i);
            }
            /*计数器,保证在计数器为0的时候才输出匹配中的字符串个数*/
            CountDownLatch countDownLatch = new CountDownLatch(3);
            MyRunnable myRunnable = new MyRunnable(countDownLatch);
            Thread thread1 = new Thread(myRunnable);
            Thread thread2 = new Thread(myRunnable);
            Thread thread3 = new Thread(myRunnable);

            thread1.start();
            thread2.start();
            thread3.start();
            /*等待所有的线程执行完毕*/
            countDownLatch.await();
            System.out.println("All 'u51' count num is: "+count);
        }
    }

}

运行结果:

这里写图片描述

猜你喜欢

转载自blog.csdn.net/MakeContral/article/details/78122769