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

来源:互联网 发布:2016淘宝店铺装修教程 编辑:程序博客网 时间:2024/04/29 14:14

前几天看到一个面试题目:有一个长度为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);        }    }}

运行结果:

这里写图片描述