• 128549

    文章

  • 807

    评论

  • 12

    友链

  • 最近新加了换肤功能,大家多来逛逛吧~~~~
  • 喜欢这个网站的朋友可以加一下QQ群,我们一起交流技术。

Java线程总结---第三天

服了这份高薪指南,涨多少你说了算>>

CountDownLatch

CountDownLatch是一个非常实用的多线程控制工具类,称之为“倒计时器”,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。

小程序

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

/**
 * @program: demo
 * @description:
 * @author: lee
 * @create: 2019-02-26
 **/
public class Demo {
    private static final int THREAD_COUNT_NUM = 7;
    private static CountDownLatch countDownLatch=new CountDownLatch(THREAD_COUNT_NUM);

    public static void main(String[] args) {

        for (int i=0;i<THREAD_COUNT_NUM;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("正在执行第的线程是====>"+Thread.currentThread().getName());
                    try {
                        Thread.sleep(new Random().nextInt(3000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("执行结束的线程是====>"+Thread.currentThread().getName());
                    countDownLatch.countDown();
                }
            }).start();
        }

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("所有线程已经执行完毕");


    }

}

输入结果

正在执行第的线程是====>Thread-0
正在执行第的线程是====>Thread-1
正在执行第的线程是====>Thread-2
正在执行第的线程是====>Thread-3
正在执行第的线程是====>Thread-4
正在执行第的线程是====>Thread-6
正在执行第的线程是====>Thread-5
执行结束的线程是====>Thread-0
执行结束的线程是====>Thread-5
执行结束的线程是====>Thread-3
执行结束的线程是====>Thread-4
执行结束的线程是====>Thread-6
执行结束的线程是====>Thread-1
执行结束的线程是====>Thread-2
所有线程已经执行完毕

CountDownLatch是在java1.5被引入的,它存在于java.util.concurrent包下。 CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。例 如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后 再执行。

CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当 一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所 有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。

CountDownLatch在实时系统中的使用场景

实现最大的并行性:有时我们想同时启动多个线程,实现最大程度的并行性。例 如,我们想测试一个单例类。如果我们创建一个初始计数为1的CountDownLatch,并 让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用 一次 countDown()方法就可以让所有的等待线程同时恢复执行。

开始执行前等待n个线程完成各自任务:例如应用程序启动类要确保在处理用户 请求前,所有N个外部系统已经启动和运行了。

CyclicBarrier

CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。

CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。

CyclicBarrier强调的是n个线程,大家相互等待,只要有一个没完成,所有人都得等着。

实例小程序

import jdk.nashorn.internal.runtime.FindProperty;

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * @program: demo
 * @description:
 * @author: lee
 * @create: 2019-02-27
 **/
public class Demo {

    private static final int THREAD_COUNT_NUM =7;

    public static void main(String[] args) {

        CyclicBarrier barrier=new CyclicBarrier(THREAD_COUNT_NUM, new Runnable() {
            @Override
            public void run() {
                System.out.println("7个线程准备完毕;");
                doSomething();
            }
        });

        for (int i=0;i<THREAD_COUNT_NUM;i++){
            int finalI = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(new Random().nextInt(5000));
                        System.out.println("第"+ finalI +"个线程准备完毕");
                        barrier.await();
                    } catch (InterruptedException | BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }

    private static void doSomething(){
        CyclicBarrier barrier=new CyclicBarrier(THREAD_COUNT_NUM, new Runnable() {
            @Override
            public void run() {
                System.out.println("7个线程的任务执行完毕;");
            }
        });

        for (int i=0;i<THREAD_COUNT_NUM;i++){
            int finalI = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(new Random().nextInt(3000));
                        System.out.println("第" + finalI + "个线程的任务执行完毕");
                        barrier.await();
                    } catch (InterruptedException | BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}    

输入结果

第0个线程准备完毕
第5个线程准备完毕
第3个线程准备完毕
第1个线程准备完毕
第2个线程准备完毕
第4个线程准备完毕
第6个线程准备完毕
7个线程准备完毕;
第2个线程的任务执行完毕
第3个线程的任务执行完毕
第1个线程的任务执行完毕
第4个线程的任务执行完毕
第5个线程的任务执行完毕
第0个线程的任务执行完毕
第6个线程的任务执行完毕
7个线程的任务执行完毕;
/**
* Resets the barrier to its initial state. If any parties are
* currently waiting at the barrier, they will return with a
* {@link BrokenBarrierException}. Note that resets <em>after</em>
* a breakage has occurred for other reasons can be complicated to
* carry out; threads need to re‐synchronize in some other way,
* and choose one to perform the reset. It may be preferable to
* instead create a new barrier for subsequent use.
*/
public void reset() { ... }

查看CyclicBarrier.reset() 可知,可以使CyclicBarrier回到最初始的状态,由于使用的相对较少。

CyclicBarrier和CountDownLatch的区别

CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用 reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。

CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。

CountDownLatch会阻塞主线程,CyclicBarrier不会阻塞主线程,只会阻塞子线 程。

CyclicBarrier和CountDownLatch的应用

可以用于一些耗时的任务的拆分,比如数据库查询的时候可以开多个线程去查询数据库,然后再把所有线程查到的数据封装起来,提高了查询的效率。

Future模式

Future设计模式就无需等待答复的到来,在等待答复的过程中可以干其他事情。

如下是简单的实现方式,不过思路挺优秀的。

参与者 作用
Main 系统启动
Client 返回Data对象,立即返回FutureData,并开启线程装配真实数据
Data 返回数据的接口
FutureData future数据,返回很快,但是是个虚拟的数据,需要装配真实的数据
RealData 真实的数据,构造数据比较慢
public interface Data {

    String getResult();
}    


public class Client {

    public Data request(String param){
        FutureData futureData=new FutureData();
        new Thread(new Runnable() {
            @Override
            public void run() {
                //装配RealData
                RealData realData = new RealData(param);
                futureData.setRealData(realData);
            }
        }).start();
        return futureData;
    }
}   

public class FutureData implements Data {

    private RealData realData = null;
    private boolean isReady = false;
    private ReentrantLock reentrantLock = new ReentrantLock();
    private Condition condition = reentrantLock.newCondition();

    @Override
    public String getResult() {
        while (!isReady){
            try {
                reentrantLock.lock();
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                reentrantLock.unlock();
            }
        }
        return realData.getResult();
    }

    public void setRealData(RealData realData){
        reentrantLock.lock();
        if (isReady){
            return;
        }
        this.realData=realData;
        isReady=true;
        condition.signal();
        reentrantLock.unlock();
    }
}

public class RealData implements Data {

    private String result;

    public RealData(String param){
        StringBuffer sb = new StringBuffer();
        sb.append(param);
        try {
        //模拟构造真实数据的耗时操作
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        result = sb.toString();
    }
    @Override
    public String getResult() {
        return result;
    }
}

/**
 * @program: demo
 * @description:
 * @author: lee
 * @create: 2019-02-27
 **/
public class Main {

    public static void main(String[] args) {
        Client client = new Client();

        Data data = client.request("Hello Future!");

        System.out.println("请求完毕");

        System.out.println("真实数据:" + data.getResult());

        System.out.println("你好,我到这里了");
    }
}  

输出结果

请求完毕
真实数据:Hello Future!
你好,我到这里了

JDK中的Future模式实现

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

/**
 * @program: demo
 * @description:
 * @author: lee
 * @create: 2019-02-27
 **/
public class FutureDemo {

    public static void main(String[] args) {
        Callable callable = new Callable() {
            @Override
            public Object call() throws Exception {
                System.out.println("我要开始处理数据啦");
                Thread.sleep(5000);  // 模拟处理时间
                System.out.println("我处理数据结束啦");
                return "这是处理后的字符串";
            }
        };

        FutureTask<String> task=new FutureTask<String>(callable);

        new Thread(task).start();


        Callable callable2 = new Callable() {
            @Override
            public Object call() throws Exception {
                System.out.println("我继续干其他的事情啦");
                return "true";
            }
        };

        FutureTask<String> task2=new FutureTask<String>(callable2);

        new Thread(task2).start();

        if (!task.isDone()){
            System.out.println("别着急还没做完呢...");
        }

        try {
            System.out.println("task2====>"+task2.get());
            System.out.println("task1====>"+task.get());

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }


    }
}    

输出结果

别着急还没做完呢...
我要开始处理数据啦
我继续干其他的事情啦
task2====>true
我处理数据结束啦
task1====>这是处理后的字符串

FutureTask的实现

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @program: demo
 * @description:
 * @author: lee
 * @create: 2019-02-27
 **/
public class FutureDemo {

    public static void main(String[] args) {
        Callable callable = new Callable() {
            @Override
            public Object call() throws Exception {
                System.out.println("我要开始处理数据啦");
                Thread.sleep(5000);  // 模拟处理时间
                System.out.println("我处理数据结束啦");
                return "这是处理后的字符串";
            }
        };

        FutureTask<String> task=new FutureTask<String>(callable);

        new Thread(task).start();


        Callable callable2 = new Callable() {
            @Override
            public Object call() throws Exception {
                System.out.println("我继续干其他的事情啦");
                return "true";
            }
        };

        FutureTask<String> task2=new FutureTask<String>(callable2);

        new Thread(task2).start();

        if (!task.isDone()){
            System.out.println("别着急还没做完呢...");
        }
        try {
            System.out.println("task2====>"+task2.get());
            System.out.println("task1====>"+task.get());

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }


    }
}    

695856371Web网页设计师②群 | 喜欢本站的朋友可以收藏本站,或者加入我们大家一起来交流技术!

0条评论

Loading...


发表评论

电子邮件地址不会被公开。 必填项已用*标注

自定义皮肤 主体内容背景
打开支付宝扫码付款购买视频教程
遇到问题联系客服QQ:419400980
注册梁钟霖个人博客