Java线程池的实际应用:一根木棍 随机分割三段 组成三角形的概率 多线程解决

        java线程池的介绍全网很多,大家可以查询得到,我就不多赘述了(讲的可能还不如那些资料好)

来看一个实际问题:

        我们有一根长度为1的木棍,现在我们随机将它分割成三份,那么这三段木棍能组成一个三角形的概率是多少?

        我相信一些精通数学的小伙伴能用通过三边关系来给出解析解的答案,但作为计算机人,我们可以借鉴伟大的蒙特卡洛方法来解决。

        (蒙特卡罗方法于20世纪40年代美国在第二次世界大战中研制原子弹的“曼哈顿计划”计划的成员S.M.乌拉姆和J.冯·诺伊曼首先提出。数学家冯·诺伊曼用驰名世界的赌城—摩纳哥的Monte Carlo—来命名这种方法,为它蒙上了一层神秘色彩。)

        我们使用java的random方法来生成一个[0,1]以内的随机数a=Math.random(),然后令b=(1-a)*Math.random(), c=1-a-b;我们就得到了三个随机数a,b,c,而且sum(a,b,c)=1。

        由三角形的特性知:三角形容易两边之和大于第三边,那么我们可以设置三个检验条件:

                                                a+b>c&&a+c>b&&c+b>a 

这样我们就得到了判断生成的随机数是否能组成三角形的结果。接下来重复这个过程,让它计算n次,就能得到答案。我们通过一个for循环解决这个问题。

使用java编程,我们将这个三角形问题封装成一个类,如果想要同时并行计算n个这样的三角形问题,一个解决方案就是使用线程池,如果要这样做的话,我们要在三角形问题中实现Runnable接口,然后重载run方法。接着在Solution类中声明一个线程池,然后将每次new出来的三角形问题使用execute方法来执行即可。(原理比使用难系列)。

话不多说,上代码吧:

import java.util.ArrayList;
import java.util.List;

public class TriangleProbability implements Runnable{
    TriangleProbability(int size,int num){
        inf=size;
        this.num=num;
    }
    TriangleProbability(){
        inf=(int)1e8;
    }
    private int inf;
    private int num;
    boolean judge(double a,double b,double c){
        if (a+b>c&&a+c>b&&b+c>a)return true;
        return false;
    }
    public double probability(){
        int cnt=0;
        for (int i = 0; i < inf; i++) {
            double a=Math.random();
            double b=(1-a)*Math.random();
            double c=1.0-a-b;
            if (judge(a,b,c)){
                cnt++;
            }
        }
        double result=((double) cnt)/((double) inf);
        return result;
    }

    @Override
    public void run() {
        System.out.println("run test "+num);
        System.out.println(probability());
    }
}

        上面是单纯实现一个三角形问题的代码,此时已经能解决问题了,但我们进一步看看使用并行计算的结果:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Solution {
    public static void main(String[] args) {
        int cnt= (int) 1e7;
        ThreadPoolExecutor executor=new ThreadPoolExecutor(8,26,300, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(6));
        for (int i = 0; i < 25; i++) {
            TriangleProbability triangleProbability=new TriangleProbability(cnt,i);
            executor.execute(triangleProbability);
            System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+
                    executor.getQueue().size()+",已执行别的任务数目:"+executor.getCompletedTaskCount());
        }
        executor.shutdown();
//      System.out.println("all the test is finished");
    }
}

        这段简单的代码中,只要把new出来的triangleProbability放到线程池的execute方法里,就行了,qaq。

        但其实想搞明白线程池还是蛮花功夫的,等有时间了我可以再深入研究一下。

附上运行结果:

run test 0
线程池中线程数目:1,队列中等待执行的任务数目:0,已执行别的任务数目:0
线程池中线程数目:2,队列中等待执行的任务数目:0,已执行别的任务数目:0
run test 1
线程池中线程数目:3,队列中等待执行的任务数目:0,已执行别的任务数目:0
线程池中线程数目:4,队列中等待执行的任务数目:0,已执行别的任务数目:0
run test 2
线程池中线程数目:5,队列中等待执行的任务数目:0,已执行别的任务数目:0
线程池中线程数目:6,队列中等待执行的任务数目:0,已执行别的任务数目:0
线程池中线程数目:7,队列中等待执行的任务数目:0,已执行别的任务数目:0
线程池中线程数目:8,队列中等待执行的任务数目:0,已执行别的任务数目:0
线程池中线程数目:8,队列中等待执行的任务数目:1,已执行别的任务数目:0
线程池中线程数目:8,队列中等待执行的任务数目:2,已执行别的任务数目:0
线程池中线程数目:8,队列中等待执行的任务数目:3,已执行别的任务数目:0
线程池中线程数目:8,队列中等待执行的任务数目:4,已执行别的任务数目:0
线程池中线程数目:8,队列中等待执行的任务数目:5,已执行别的任务数目:0
线程池中线程数目:8,队列中等待执行的任务数目:6,已执行别的任务数目:0
线程池中线程数目:9,队列中等待执行的任务数目:6,已执行别的任务数目:0
线程池中线程数目:10,队列中等待执行的任务数目:6,已执行别的任务数目:0
线程池中线程数目:11,队列中等待执行的任务数目:6,已执行别的任务数目:0
线程池中线程数目:12,队列中等待执行的任务数目:6,已执行别的任务数目:0
线程池中线程数目:13,队列中等待执行的任务数目:6,已执行别的任务数目:0
线程池中线程数目:14,队列中等待执行的任务数目:6,已执行别的任务数目:0
线程池中线程数目:15,队列中等待执行的任务数目:6,已执行别的任务数目:0
线程池中线程数目:16,队列中等待执行的任务数目:6,已执行别的任务数目:0
线程池中线程数目:17,队列中等待执行的任务数目:6,已执行别的任务数目:0
线程池中线程数目:18,队列中等待执行的任务数目:6,已执行别的任务数目:0
线程池中线程数目:19,队列中等待执行的任务数目:6,已执行别的任务数目:0
all the test is finished
run test 3
run test 4
run test 14
run test 6
run test 7
run test 16
run test 17
run test 20
run test 21
run test 24
run test 15
run test 5
run test 18
run test 19
run test 22
run test 23
0.1930215
run test 8
0.1930061
run test 9
0.1929787
run test 10
0.1930489
run test 11
0.1930994
run test 12
0.1932215
run test 13
0.1929723
0.19309
0.1933499
0.1931939
0.1931726
0.19289
0.1930908
0.1930913
0.1933291
0.1931412
0.1930616
0.1930444
0.1932149
0.1931634
0.1934008
0.1932558
0.1933119
0.1930957
0.1931464

Process finished with exit code 0

可以看到每次运行的结果稳定在0.193附近,如果通过数学方法计算,那么概率的数学期望是0.2,

让我们粗略的估计一下最大误差:(0.2-0.193)/0.2=0.035=3.5% 我认为这个误差范围是可以接受的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值