Java:线程并发工具类

标签: java 线程 并发 | 发表时间:2016-09-28 08:05 | 作者:p106786860
出处:http://blog.csdn.net
一、CountDownLatch 
1.应用场景
 
在实际多线程并发开发过程中,我们会碰见很多等待子线程完毕后在继续执行的情况,(如多个子线程下载文件,所有子线程执行完毕后再重命名为文件名)。 
2.使用方式 
CountDownLatch的构造函数接受一个int类型的参数作为计数器,调用countDwon()方法,计数器减1,await()方法阻塞当前线程,直到计数器变为0;、 
补充: 
    计数器为0的时候,调用awaite()方法不会阻塞主线程; 
    初始化后,不能修改计数器的值; 
    可以使用await(long time,TimeUnit unit)等待特定时间后,就不阻塞主线程; 
3.实例代码 
public class Main { 
    //等待2个子线程执行完毕,计数器为2 
    static CountDownLatch countDownLatch = new CountDownLatch(2); 
 
    public static void main(String[] args) { 
        System.out.println("start subThread doing..."); 
        //创建并开启2个子线程 
        SubThread subThread1 = new SubThread(); 
        SubThread subThread2 = new SubThread(); 
        subThread1.start(); 
        subThread2.start(); 
 
        try { 
            //阻塞主线程,等待子线程结束 
            countDownLatch.await(); 
        } catch (InterruptedException e) { 
            e.printStackTrace(); 
        } 
 
        System.out.println("subThread are finish..."); 
    } 
 
    static class SubThread extends Thread { 
        @Override 
        public void run() { 
            //模拟执行任务 
            try { 
                sleep(3000); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
            //子线程执行完毕,减少计数器 
            countDownLatch.countDown(); 
            System.out.println(getName() + " done..."); 
        } 
    } 
} 
运行结果:当Thread-1、Thread-0两个子线程执行完毕后,在运行main线程后续的逻辑 
start subThread doing... 
Thread-1 done... 
Thread-0 done... 
subThread are finish... 
二、CyclicBarrier 
1.应用场景 

如果当你遇见需要让一组线程达到同一个屏障(同步点)时被阻塞,直到最后一个线程达到屏障时,屏障才会打开的情况。 
2.使用方式 
CycliBarrier默认的构造方法CyclicBarrier(int parties),参数标识屏障拦截的线程个数,每个线程调用await()方法告诉SyclicBarrier我们已经达到屏障了,然后当前线程被阻塞。当所有子线程都达到屏障后,则继续执行子线程的后续逻辑。 
补充: 
CyclicBarrier还提供了一个更高级的函数CyclicBarrier(int parties,Runnable barrierAction),用于在线程达到屏障时,优先执行barrierAction。 
3.实例代码 
public class Main { 
    //拦截2个子线程屏障 
    static CyclicBarrier cyclicBarrier = new CyclicBarrier(2); 
 
    public static void main(String[] args) { 
        System.out.println("start subThread doing..."); 
        SubThread subThread1 = new SubThread(); 
        SubThread subThread2 = new SubThread(); 
        subThread1.start(); 
        subThread2.start(); 
    } 
 
    static class SubThread extends Thread { 
        @Override 
        public void run() { 
            try { 
                System.out.println(getName() + " doing first things."); 
                //模拟子线程执行第一个任务 
                sleep(3000); 
                System.out.println(getName() + " done first things."); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
             
            try { 
                //完成第一个任务,告知达到屏障 
                cyclicBarrier.await(); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } catch (BrokenBarrierException e) { 
                e.printStackTrace(); 
            } 
 
 
            //所有子线程都完成第一个任务后,继续运行每个子线程的下一个任务 
            System.out.println(getName() + " doing other things."); 
        } 
    } 
} 
运行结果:当子线程都执行完第一个任务到达屏障后,执行下一个任务 
start subThread doing... 
Thread-0 doing first things. 
Thread-1 doing first things. 
Thread-1 done first things. 
Thread-0 done first things. 
Thread-0 doing other things. 
Thread-1 doing other things.
三、Semaphore 
1.应用场景
 
多线程访问公共资源的情况在开发过程中经常遇见,如数据库连接,可能开启几十个线程进行并发读取,但是考虑到数据库连接性能和消耗,我们必须控制10个线程哪个是连接数据库。Semaphore就是用来控制同时访问特定资源的线程数量。 
2.使用方式 
Semaphore的构造方法Semaphore(int permits),permits标识许可证数量。执行任务前,acquire()方法获取一个许可证;任务执行完成后调用relese()方法归还许可证。没有获得许可证的子线程就阻塞等待。 
补充: 
tryAcquire():尝试获取许可证; 
intavaliablePermits():返回信号量中当前许可证的个数; 
intgetQueueLength():返回正在等待获取许可证的线程个数; 
booleanhasQueueThreads():是否有线程正在等待许可证; 
reducePermits(int reduction):减少reduction个许可证; 
getQueuedThreads():返回所有等待获取许可证的线程集合; 
3.实例代码 
public class Main { 
    //创建2个许可证 
    static Semaphore semaphore = new Semaphore(2); 
 
    public static void main(String[] args) { 
        System.out.println("start subThread doing..."); 
        //同时开启4个子线程运行 
        for (int i = 0; i < 4; i++) { 
            SubThread subThread = new SubThread(); 
            subThread.start(); 
        } 
    } 
 
    static class SubThread extends Thread { 
        @Override 
        public void run() { 
            try { 
                //执行任务前获取许可证 
                semaphore.acquire(); 
                System.out.println(getName() + "doing things."); 
                sleep(3000); 
                //执行完任务释放许可证 
                semaphore.release(); 
                System.out.println(getName() + "finish things."); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        } 
    } 
} 
运行结果:同时只有2个线程运行,当某个线程运行完毕释放许可后,下一个线程才获取许可运行; 
start subThread doing... 
Thread-0doing things. 
Thread-1doing things. 
Thread-1finish things. 
Thread-2doing things. 
Thread-0finish things. 
Thread-3doing things. 
Thread-2finish things. 
Thread-3finish things. 
四、Exchanger 
1.应用场景 

在某些实际业务如流水录入中,为了避免错误。采用两个人同时录入,并对比录入的结果是否一致。Exchanger用于进行线程之间的数据交换,它提供了一个同步点,两个线程可以交换彼此的数据。 
2.使用方式 
两个线程通过exchange()方法交换数据,如果一个线程执行exchange()方法,它会一直等待第二个线程也执行exchange()方法。当两个线程都达到同步点时,就可以交换数据,将本线程产生的数据传递给对方。 
3.实例代码 
public class Main { 
    //用户线程间交换数据(String)对象exchanger 
    static Exchanger<String> exchanger = new Exchanger<>(); 
 
    public static void main(String[] args) { 
        //创建2个子线程分别执行 
        SubThread1 subThread1 = new SubThread1(); 
        SubThread2 subThread2 = new SubThread2(); 
        subThread1.start(); 
        subThread2.start();  
    } 
 
    static class SubThread1 extends Thread { 
        @Override 
        public void run() { 
            try { 
                System.out.println(getName() + "start doing..."); 
                //模拟执行完成后,获取结果result1,并将result1交换给对方线程 
                sleep(3000); 
                String result1 = "3000"; 
                String result2 = exchanger.exchange(result1); 
                //待两个线程都执行完毕后,交换数据进行比较 
                System.out.println(getName() + " thread1 result:" + result1 + " is equals thread2 result:" + result2 + 
                        "," + result1.equals(result2)); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        } 
    } 
 
    static class SubThread2 extends Thread { 
        @Override 
        public void run() { 
            try { 
                System.out.println(getName() + "start doing..."); 
                //模拟执行完成后,获取结果result2,并将result2交换给对方线程 
                sleep(2000); 
                String result2 = "2000"; 
                String result1 = exchanger.exchange(result2); 
                //待两个线程都执行完毕后,交换数据进行比较 
                System.out.println(getName() + " thread1 result:" + result1 + " is equals thread2 result:" + result2 + 
                        "," + result1.equals(result2)); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        } 
    } 
} 
运行结果:线程1优先执行完毕,等待线程0执行完毕后,交换数据分别进行结果比较 
Thread-1start doing... 
Thread-0start doing... 
Thread-1finish doing... 
Thread-0finish doing... 
Thread-0 thread1 result:3000 is equals thread2 result:2000,false 
Thread-1 thread1 result:3000 is equals thread2 result:2000,false 
作者:p106786860 发表于2016/9/28 0:05:58 原文链接
阅读:156 评论:0 查看评论

相关 [java 线程 并发] 推荐:

Java 多线程 (并发)总结

- - CSDN博客推荐文章
《进程与线程的一个简单解释》 简单摘要如下. 电力有限,一次只能供给一个车间使用. 进程的内存是共享的,每个线程都能使用. 一个线程使用内存空间时,其他线程必须等它结束. 车间厕所,有人时其他人不能进入. 某内存空间,仅供固定数目线程使用. 挂N把锁,进入的人拿钥匙锁上,出来时放回. (1)Runnable接口  (通常选择这种,接口本身可以实现多重继承,比较灵活).

Java:线程并发工具类

- - CSDN博客编程语言推荐文章
一、CountDownLatch . 在实际多线程并发开发过程中,我们会碰见很多等待子线程完毕后在继续执行的情况,(如多个子线程下载文件,所有子线程执行完毕后再重命名为文件名). CountDownLatch的构造函数接受一个int类型的参数作为计数器,调用countDwon()方法,计数器减1,await()方法阻塞当前线程,直到计数器变为0;、 .

JAVA多线程和并发基础面试问答

- - 企业架构 - ITeye博客
原文链接    译文连接  作者:Pankaj   译者: 郑旭东   校对:方腾飞. 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一. 在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌握Java多线程基础知识来对应日后碰到的问题. ( 校对注:非常赞同这个观点).

使用SPRING中的线程池ThreadPoolTaskExecutor实现JAVA并发

- - Java - 编程语言 - ITeye博客
//线程池所使用的缓冲队列 . //线程池维护线程的最少数量 . //线程池维护线程的最大数量 . //线程池维护线程所允许的空闲时间 .  .      .      .      .

Java线程池

- - 企业架构 - ITeye博客
线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的. 在jdk1.5之后这一情况有了很大的改观. Jdk1.5之后加入了java.util.concurrent包,这个包中主要介绍java中线程以及线程池的使用. 为我们在开发中处理线程的问题提供了非常大的帮助.

Java 线程池

- - 编程语言 - ITeye博客
在项目中,系统启动一个新线程的成本是比较高的,因为它涉及与操作系统交互. 在这种情形下,使用线程池可以很好地提高性能,尤其是当程序中需要创建大量生存周期很短的线程时,更应该考虑使用线程池. 使用线程池可以有效地控制系统中并发线程的数量,当系统中包含大量并发线程时,会导致系统性能剧烈下降,甚至导致JVM崩溃,而线程池的最大线程数参数可以控制系统中并发线程数不超过此数.

Java Thread多线程

- - CSDN博客推荐文章
Java Thread多线程. Java 多线程例子1 小例子. super("zhuyong");//设置线程的名字,默认为“TestThread”. Java 多线程例子2 前台线程(用户线程) 后台线程(守护线程 ). 1,setDaemon(true)后就是后台线程(守护线程 ),反之就是前台线程(用户线程).

Java线程之FutureTask

- - zzm
FutureTask是Future和Callable的结合体. 然后通过Future来取得计算结果. 但是,若开启了多个任务,我们无从知晓哪个任务最先结束,因此,若要实现“当某任务结束时,立刻做一些事情,例如记录日志”这一功能,就需要写一些额外的代码. FutureTask正是为此而存在,他有一个回调函数protected void done(),当任务结束时,该回调函数会被触发.

[Java] Java 多线程案例分析

- - V2EX
现要从 hbase中导出 2016 年整年的,大约 10w只股票行情数据,数据总量约 100t. 汇总到 hdfs中供需求方使用. 已知数据量规模大概是 100t,那么单台机器处理肯定不是不行的,先不说大多数磁盘都没这么大,即便磁盘有这么大,单台机器处理对于内存和 cpu 要求也很高,所以我们将问题一般化,使用数量有限的低配机器.