04.Java多线程并发库API使用3

1.java5的Semaphere同步工具

Semaphore可以维护当前访问自身的线程个数,并提供了同步机制。使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。

Semaphore实现的功能就类似银行有6个窗口,12个人有业务要操作,那么同时只能有6个人占用窗口,当有的人业务操作完毕之后,让开位置,其它等待的人群中,有一人可以占用当前窗口,操作自己的业务。

另外等待的5个人中可以是随机获得优先机会,也可以是按照先来后到的顺序获得机会,这取决于构造Semaphore对象时传入的参数选项。

单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。

package com.chunjiangchao.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * 同步信号量的使用
 * @author chunjaingchao
 * 随时可以调整Semaphore中可并发的数量
 */
public class SemaphoreDemo {

    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(1);//允许的并发数
        for(int i=0;i<10;i++){
            threadPool.execute(new Runnable(){

                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在执行,当前已经有"+(1-semaphore.availablePermits())+"个并发");
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    semaphore.release();

                }

            });
        }
    }

}

2.CyclicBarrier同步工具

表示大家彼此等待,大家集合好后才开始出发,分散活动后又在指定地点集合碰面,这就好比整个公司的人员利用周末时间集体郊游一样,先各自从家出发到公司集合后,再同时出发到公园游玩,在指定地点集合后再同时开始就餐,…。

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

package com.chunjiangchao.thread;

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * CyclicBarrier的使用
 * @author chunjiangchao
 *
 */
public class CyclicBarrierDemo {

    public static void main(String[] args) {
        final int threadNum = 5;
        ExecutorService threadPool = Executors.newCachedThreadPool();
        final CyclicBarrier cb = new CyclicBarrier(threadNum);
        for(int i=0;i<threadNum;i++){
            threadPool.execute(new Runnable(){

                @Override
                public void run() {
                    try {
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("线程"
                                + Thread.currentThread().getName()
                                + "运行到Barrier1,已有"+ (cb.getNumberWaiting() + 1)+ "个已经到达,"
                                + (cb.getNumberWaiting() == threadNum-1 ? "都到齐了,继续走啊"
                                        : "正在等候"));
                        cb.await();//障碍点1:当前线程在await这个障碍地点停顿,等着其它线程运行到这
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("线程"
                                + Thread.currentThread().getName()
                                + "运行到Barrier2,已有"+ (cb.getNumberWaiting() + 1)+ "个已经到达,"
                                + (cb.getNumberWaiting() == threadNum-1 ? "都到齐了,继续走啊"
                                        : "正在等候"));
                        cb.await();//障碍点2:
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("线程"
                                + Thread.currentThread().getName()
                                + "运行到Barrier3,已有"+ (cb.getNumberWaiting() + 1)+ "个已经到达,"
                                + (cb.getNumberWaiting() == threadNum-1 ? "都到齐了,继续走啊"
                                        : "正在等候"));
                        cb.await();//障碍点3:
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }

            });
        }
        //正在执行的任务接着执行,后续不允许添加任务
        threadPool.shutdown();
    }

}

3.java5的CountDownLatch同步工具

一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

犹如倒计时计数器,调用CountDownLatch对象的countDown方法就将计数器减1,当计数到达0时,则所有等待者或单个等待者开始执行。

可以实现一个人(也可以是多个人)等待其他所有人都来通知他,这犹如一个计划需要多个领导都签字后才能继续向下实施。还可以实现一个人通知多个人的效果,类似裁判一声口令,运动员同时开始奔跑。用这个功能做百米赛跑的游戏程序不错哦!

package com.chunjiangchao.thread;

import java.util.Random;
import java.util.concurrent.CountDownLatch;

/**
 * 创建这个CountDownLatch对象的时候,会传入计数器个数,当前线程调用await方法进行等待其它线程的操作,
 * 当其他线程操作计数器的值直到0的时候,才会继续执行后续操作
 * @author chuangjiangchao
 *
 */
public class CountDownLatchDemo {

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        for(int i=0;i<3;i++){
            new WorkThread(countDownLatch).start();
        }
        System.out.println("老大在这儿等着");
        countDownLatch.await();
        System.out.println("你们都跑完了,该我走人了");

    }
    private static class WorkThread extends Thread{
        private CountDownLatch countDownLatch;
        public WorkThread(CountDownLatch countDownLatch){
            this.countDownLatch = countDownLatch;
        }
        @Override
        public void run() {
            System.out.println("执行耗时的操作");
            try {
                Thread.sleep(100*new Random().nextInt(100));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            countDownLatch.countDown();
            System.out.println(Thread.currentThread().getName()+"跑完任务,计数器值改变");
        }
    }

}

4.java5的Exchanger同步工具

用于实现两个线程之间的数据交换,每个线程在完成一定的事务后想与对方交换数据,第一个先拿出数据的线程将一直等待第二个线程拿着数据到来时,才能彼此交换数据。

(谁先到达,谁就等待另外一个线程到达,然后开始交换数据。最后执行各自的动作。)

package com.chunjiangchao.thread;

import java.util.Date;
import java.util.Random;
import java.util.concurrent.Exchanger;

/**
 * 两个线程之间的数据交换
 * @author chunjiangchao
 *
 */
public class ExchangerDemo {

    public static void main(String[] args) {
        Exchanger<String> exchanger = new Exchanger<String>();//通过这玩意儿来交换数据
//        ExecutorService threadPool = Executors.newCachedThreadPool();
//        threadPool.execute(command);
        new ThreadA(exchanger).start();
        new ThreadB(exchanger).start();
    }
    private static class ThreadA extends Thread{
        private Exchanger<String> exchanger;
        public ThreadA(Exchanger<String> exchanger){
            this.exchanger = exchanger;
        }
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName()+"执行之前"+new Date().toLocaleString());
                Thread.sleep(new Random().nextInt(100)*100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                System.out.println(Thread.currentThread().getName()+"开始交换数据"+new Date().toLocaleString());
                String exchange = exchanger.exchange("A的数据");//给我等着,直到需要交换数据的线程B到来
                System.out.println(Thread.currentThread().getName()+"交换后得到的数据:"+exchange);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
    private static class ThreadB extends Thread{
        private Exchanger<String> exchanger;
        public ThreadB(Exchanger<String> exchanger){
            this.exchanger = exchanger;
        }
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName()+"执行之前"+new Date().toLocaleString());
                Thread.sleep(new Random().nextInt(100)*100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                System.out.println(Thread.currentThread().getName()+"开始交换数据"+new Date().toLocaleString());
                String exchange = exchanger.exchange("B的数据");
                System.out.println(Thread.currentThread().getName()+"交换后得到的数据:"+exchange);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

}

5.java5阻塞队列的应用(ArrayBlockingQueue)

阻塞队列与Semaphore有些相似,但也不同,阻塞队列是一方存放数据,另一方释放数据,Semaphore通常则是由同一方设置和释放信号量(主要控制访问资源的线程数)。

ArrayBlockingQueue :只有put方法和take方法才具有阻塞功能。

package com.chunjiangchao.thread;

import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;

/**
 * 两个生产者,一个消费者
 * @author chunjiangchao
 *
 */
public class ArrayBlockingQueueDemo {

    public static void main(String[] args) {
        final ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(3);
        for(int i=0;i<2;i++){
            new Thread(new Runnable() {

                @Override
                public void run() {
                    while(true){
                        try {
                            Thread.sleep(3000);
                            int nextInt = new Random().nextInt(100);
                            System.out.println(Thread.currentThread().getName()+"添加数据为:"+nextInt);
                            queue.put(nextInt);//当前操作与take操作是阻塞的
                            System.out.println("当前数据个数"+queue.size());
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }

        new Thread(new Runnable() {

            @Override
            public void run() {
                while(true){
                    try {
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName()+"获取数据");
                        Integer take = queue.take();//取数据,如果queue里面没有数据,就会一直等,等queue里面存放数据了,才会执行后续的代码
                        System.out.println("获取到的数据为"+take+" ,当前数据个数"+queue.size());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

    }

}

问题:用两个具有1个空间的队列来实现同步通知的功能

package com.chunjiangchao.thread;

import java.util.concurrent.ArrayBlockingQueue;

/**
 * 使用BlockingQueue实现同步通知的功能
 * @author zzb
 *
 */
public class BlockingQueueCommunicationDemo {

    public static void main(String[] args) {
        final Business business = new Business();
        Thread threadMain = new Thread(new Runnable(){
            @Override
            public void run() {
                while(true){
                    try {
                        business.main();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        });
        threadMain.setName("threadMain");
        threadMain.start();
        Thread threadSub = new Thread(new Runnable(){

            @Override
            public void run() {
                while(true){
                    try {
                        business.sub();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        });
        threadSub.setName("threadSub");
        threadSub.start();
        /*
         * 你一下我一下,你一下,我一下
             threadMain执行耗时操作
            threadSub执行耗时操作
            threadMain执行耗时操作
            threadSub执行耗时操作
            threadMain执行耗时操作
            threadSub执行耗时操作

         */
    }
    private static class Business{
        private static ArrayBlockingQueue<Integer> mainQueue = new ArrayBlockingQueue<>(1);
        private static ArrayBlockingQueue<Integer> subQueue = new ArrayBlockingQueue<>(1);
        static{
            try {
                mainQueue.put(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        public void sub() throws InterruptedException{
            subQueue.take();//sub在subQueue取出数据,取不到数据,就等着
            System.out.println(Thread.currentThread().getName()+"执行耗时操作");
            Thread.sleep(3000);
            mainQueue.put(1);//存放数据到subQueue,方便
        }
        public void main() throws InterruptedException{
            mainQueue.take();//main在mainQueue取出数据,取不到数据,就等着
            System.out.println(Thread.currentThread().getName()+"执行耗时操作");
            Thread.sleep(3000);
            subQueue.put(1);//存放数据到subQueue,方便
        }
    }

}

未完待续……

时间: 2024-10-19 06:07:52

04.Java多线程并发库API使用3的相关文章

03.Java多线程并发库API使用2

1.多个线程之间共享数据的方式探讨 1.如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,买票系统就可以这么做. 2.如果每个线程执行的代码不同,这时候需要用不同的Runnable对象,有如下两种方式来实现这些Runnable对象之间的数据共享: 将共享数据封装在另外一个对象中,然后将这个对象逐一传递给各个Runnable对象.每个线程对共享数据的操作方法也分配到那个对象身上去完成,这样容易实现针对该数据进行的各个操作的互斥和通信.

对JAVA多线程 并发编程的理解

对JAVA多线程并发编程的理解 Java多线程编程关注的焦点主要是对单一资源的并发访问,本文从Java如何实现支持并发访问的角度,浅析对并发编程的理解,也算是对前段时间所学的一个总结. 线程状态转换 Java语言定义了5中线程状态,在任何一个时间点,一个线程只能有且只有其中一种状态,这5中状态分别是: ?  新建(New):创建后尚未启动的线程处于这种状态 ?  运行(Runable):Runable包括了操作系统线程状态中的Running和Ready,也就是处于此状态的线程可能正在执行,也有可

Java多线程并发09——如何实现线程间与线程内数据共享

本文将为各位带来 Java 阻塞队列相关只是.关注我的公众号「Java面典」了解更多 Java 相关知识点. 线程间数据共享 Java 里面进行多线程通信的主要方式就是共享内存的方式,共享内存主要的关注点有两个:可见性和有序性原子性.Java 内存模型(JMM)解决了可见性和有序性的问题,而锁解决了原子性的问题,理想情况下我们希望做到"同步"和"互斥".有以下常规实现方法: 将数据抽象成一个类 将数据抽象成一个类,并将对这个数据的操作作为这个类的方法,这么设计可以和

Java高并发秒杀API之业务分析与DAO层

课程介绍 高并发和秒杀都是当今的热门词汇,如何使用Java框架实现高并发秒杀API是该系列课程要研究的内容.秒杀系列课程分为四门,本门课程是第一门,主要对秒杀业务进行分析设计,以及DAO层的实现.课程中使用了流行的框架组合SpringMVC+Spring+MyBatis,还等什么,赶快来加入吧! 第1章 课程介绍 本章介绍秒杀系统的技术内容,以及系统演示.并介绍不同程度的学员可以学到什么内容. 第2章 梳理所有技术和搭建工程 本章首先介绍秒杀系统所用框架和技术点,然后介绍如何基于maven搭建项

2017.4.26 慕课网--Java 高并发秒杀API(一)

Java高并发秒杀API系列(一) -----------------业务分析及Dao层 第一章 课程介绍 1.1 内容介绍及业务分析 (1)课程内容 1 SSM框架的整合使用 2 秒杀类系统需求理解和实现 3 常用技术解决高并发问题 (2)SSM框架 (3)为何选择秒杀系统 1 秒杀系统具有典型的"事务"特性 2 秒杀/红包类需求越来越常见 3 面试常用问题 1.3 项目效果演示 第二章 梳理所有技术和搭建工程 2.1 相关技术介绍 2.2 创建项目和依赖 第三章 秒杀业务分析 3.

java 多线程并发问题总结

java 多线程并发主要通过关键字synchronized实现 Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行.另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块. 二.然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该ob

Java多线程并发技术

Java多线程并发技术 参考文献: http://blog.csdn.net/aboy123/article/details/38307539 http://blog.csdn.net/ghsau/article/category/1707779 http://www.iteye.com/topic/366591 JAVA多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现有返回结果的多线程.其中前两种方式

知识链-Java多线程并发

Java多线程并发 java并发容器(Map.List.BlockingQueue)

imooc课程:Java高并发秒杀API 记录

Java高并发秒杀API之业务分析与DAO层 Java高并发秒杀API之Service层 Java高并发秒杀API之web层 Java高并发秒杀API之高并发优化 除了并发部分外的这个web开发的总结:https://www.imooc.com/video/11737 springmvc运行流程 BOOTSTRAP 和 JS 的使用技巧.(模块化.不混乱.抽取字典方便修改) JQ插件(countDown && cookie 等) 原文地址:https://www.cnblogs.com/a