[Java学习日记]多线程练习、线程池

目录

一.案例:五个人抢红包

二.案例:两个抽奖池抽奖

三.案例:两个抽奖池抽奖:获取线程运行的结果

四.线程池:用来存放线程,避免多次重复创建线程

五.自定义线程池

六.最大并行数与线程池大小


一.案例:五个人抢红包

1.如何保证只留下两位小数,并且计算精确呢?
使用大浮点数类,使用setScale方法保留小数
2.如何保证随机的数字最小是一分钱呢?
设置最小中奖金额,如果随机到的数字小于这个数的话,就让这个数变成这个最小金额
同时也需要保证最大的金额不会大到把剩下人的一分钱(最小金额)也给吞掉了
3.如果说是最后一个抽到红包的,还应该去随机数字吗
直接把剩余的钱款给最后一个即可

在这里的随机金额中先抢的概率更大-这或许也是不合理的地方
public class Demo321 {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();
        MyThread t4 = new MyThread();
        MyThread t0 = new MyThread();
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t0.start();
    }
}
public class MyThread extends Thread {
    static BigDecimal money = BigDecimal.valueOf(100);
    static int count = 3;
    static final BigDecimal MIN = BigDecimal.valueOf(0.01);
    @Override
    public void run() {
        synchronized (MyThread.class) {
            if (count == 0) {
                System.out.println(Thread.currentThread().getName() + "来晚一步!");
                return;
            }
            BigDecimal price;
            if (count == 1) price = money;
            else
                price = BigDecimal.valueOf(new Random().nextDouble(MIN.doubleValue(),
                        money.subtract(BigDecimal.valueOf(count-1).multiply(MIN)).doubleValue()));
            count--;
            price = price.setScale(2, RoundingMode.HALF_UP);
            money = money.subtract(price);
            System.out.println(Thread.currentThread().getName() + "抢到了" + price + "元");
        }
    }
}

 


二.案例:两个抽奖池抽奖

public class Demo322 {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t0 = new MyThread();
        t1.start();
        t0.start();
        System.out.println("到这一行就开启了三条线程");
        System.out.println("main方法是运行在main线程中的栈,线程12开启的时候在内存中会多出两个栈:线程一的方法栈和线程2的方法栈");
    }
}
public class MyThread extends Thread {
    static ArrayList<Integer> arrayList;
    static {
        arrayList = new ArrayList<>();
        Collections.addAll(arrayList, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700);
    }
    @Override
    public void run() {
        ArrayList<Integer> myArraylist = new ArrayList<>();
        while (true) {
            synchronized (MyThread.class) {
                if (arrayList.size() == 0) break;
                int index = new Random().nextInt(arrayList.size());
                Integer i = arrayList.get(index);
                arrayList.remove(index);
                myArraylist.add(i);
            }
        }
        synchronized (Thread.class) {
            if (myArraylist.size() == 0) {
                System.out.println("在此抽奖过程中,"+getName() + "没有产生任何奖项");
                return;
            }
            System.out.println("在此抽奖过程中," + getName() + "共产生了" + myArraylist.size() + "个奖项" + "分别为");
            StringJoiner sj = new StringJoiner(",");
            Integer count = 0;
            Integer max = myArraylist.get(0);
            for (Integer integer : myArraylist) {
                sj.add(integer + "");
                count += integer;
                if (integer > max) max = integer;
            }
            System.out.println(sj + "," + "最高奖项为" + max + "元," + "总计额为" + count + "元");
        }
    }
}


三.案例:两个抽奖池抽奖:获取线程运行的结果

public class Demo323 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
       MyCallable myCallable = new MyCallable();
        System.out.println("需要注意的点:这里要创建两个多线程运行结果的管理对象");
       FutureTask<Integer> futureTask0 = new FutureTask<>(myCallable);
       FutureTask<Integer> futureTask1= new FutureTask<>(myCallable);
       Thread t0 = new Thread(futureTask0);
       Thread t1 = new Thread(futureTask1);
       t0.start();
       t1.start();
       Integer i0 = futureTask0.get();
       Integer i1 = futureTask1.get();
       System.out.println("在这个抽奖过程中");
       if (i1==null||i0>i1){
           System.out.print(t0.getName()+"抽到了最大奖项,该奖金金额为:"+i0+"元");
       }else {
           System.out.print(t1.getName()+"抽到了最大奖项,该奖金金额为:"+i1+"元");
       }
    }
}
class MyCallable implements Callable<Integer> {
    static ArrayList<Integer> arrayList;
    static {
        arrayList = new ArrayList<>();
        Collections.addAll(arrayList, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700);
    }
    @Override
    public Integer call(){
        ArrayList<Integer> myArraylist = new ArrayList<>();
        while (true) {
            synchronized (MyThread.class) {
                if (arrayList.size() == 0) break;
                int index = new Random().nextInt(arrayList.size());
                Integer i = arrayList.get(index);
                arrayList.remove(index);
                myArraylist.add(i);
            }
        }
        synchronized (Thread.class) {
            if (myArraylist.size() == 0) {
                System.out.println("在此抽奖过程中,"+Thread.currentThread().getName() + "没有产生任何奖项");
                return null;
            }
            System.out.println("在此抽奖过程中," + Thread.currentThread().getName()  + "共产生了" + myArraylist.size() + "个奖项" + "分别为");
            StringJoiner sj = new StringJoiner(",");
            Integer count = 0;
            Integer max = myArraylist.get(0);
            for (Integer integer : myArraylist) {
                sj.add(integer + "");
                count += integer;
                if (integer > max) max = integer;
            }
            System.out.println(sj + "," + "最高奖项为" + max + "元," + "总计额为" + count + "元");
            return max;
        }
    }
}


四.线程池:用来存放线程,避免多次重复创建线程

提交任务时,线程池会创建新的线程对象,任务执行完毕之后,线程归还给池子
1.下次再创建任务的时候还需要创建新的线程吗?
不需要再创建新的线程,复用已经有的线程即可
2.如果提交任务的时候池子里面没有空闲线程,就无法创建新的线程,任务会如何进行?
任务就会排队等待

3.线程池创建过程?
1.创建线程池
2.提交任务
3.所有任务执行完毕时,关闭线程池(实际开发中线程池一般不会关闭)

4.创建线程池的快速方法?
使用Executors(执行人)的静态方法创建线程池

5.如何创建无上限的线程池?
6.如何提交任务?
7.如何停止线程?
8.如何创建有上限的线程池?
public class Demo324 {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("5.使用Executors的newCachedThread方法获取线程池对象(cached-缓存),无上限");
        ExecutorService pool = Executors.newCachedThreadPool();

        System.out.println("6.使用线程池的submit方法提交任务,这里的输出的线程池名字与线程名字编号都是从1开始的");
        pool.submit(new MyRunnable());
        pool.submit(new MyRunnable());
        Thread.sleep(1000);
        //在这里睡了一小会之后使用的还是原来的线程:不会创建新的线程(用线程一还是线程二是随机的)
        pool.submit(new MyRunnable());

        Thread.sleep(1000);
        System.out.println("7.使用线程池的shutdown方法停止线程");
        pool.shutdown();

        Thread.sleep(1000);

        System.out.println("8.使用Executors的newFixedThreadPool方法创建有上限的线程池");
        pool = Executors.newFixedThreadPool(1);
        pool.submit(new MyRunnable());
        pool.submit(new MyRunnable());
        pool.shutdown();
    }
}
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

 


五.自定义线程池

自定义线程池 参数如下:
1.核心线程数量(核心员工)
2.线程中最大线程数量(包括临时员工)
3.4.临时线程空闲时间与单位(临时员工存活时间)
5.阻塞队列
6.创建线程的方式
7.要执行任务过多的解决方案

创建临时线程的时机是在什么时候?
阻塞队列满了之后才能创建,不是核心线程被占满了才创建,创建临时线程处理队伍之外的任务!
public class Demo325 {
    public static void main(String[] args) {
        ThreadPoolExecutor tpe = new ThreadPoolExecutor(
                3,
                6,
                60,
                TimeUnit.SECONDS,//时间单位
                new ArrayBlockingQueue<>(3),//不想指定长度就写LinkedArrayBlockingQueue
                Executors.defaultThreadFactory(),//创建线程工厂,底层是创建Thread线程
                new ThreadPoolExecutor.AbortPolicy()//静态内部类(依赖于线程池,单独存在无意义),任务的默认拒绝策略:抛错
        );
        tpe.submit(new MyRunnable());
        tpe.submit(new MyRunnable());
        tpe.submit(new MyRunnable());
        tpe.submit(new MyRunnable());
        tpe.submit(new MyRunnable());
        tpe.submit(new MyRunnable());
        tpe.submit(new MyRunnable());
        tpe.submit(new MyRunnable());
        tpe.submit(new MyRunnable());
        tpe.shutdown();
    }
}

在上面代码基础上再加一个线程会报错: 


六.最大并行数与线程池大小

最大并行数:和CPU有关
Intel利用-超线程技术-使得每个核有两个线程
在设备管理器可以查看
1.如何获取最大能够使用的线程?

2.线程池开多大合适呢?
项目一般分为:CPU密集型(计算比较多)和IO密集型(读写文件多)
CPU密集型:
PU运算比较多,最大并行数+1(1是备用池)即可
IO密集型(大多数项目):
最大并行数(8)*期望CPU利用率(占满100%)*[(计算时间+等待时间(等待IO流))/计算时间]这个需要用工具(thread dump)计算
public class Demo326 {
    public static void main(String[] args) {
        System.out.println("2.使用Runtime.getRuntime().availableProcessors()获取当前最多能够使用的线程");
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/219124.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Android】Glide的简单使用(上)

文章目录 引入Glide的优点:缺点: 使用常用方法:从网络加载图片从文件加载图片加载resource资源加载URI地址设置占位图出错时的图片占位图图片过渡的Transitions自定义过渡动画图片大小调整缩放图片播放gifasGif()把Gif当作Bitmap播放显示本地视频缩略图 引入 Glide是Google员工…

IntelliJ IDEA 2023.2新特性详解第三弹!Docker、Kubernetes等支持!

9 Docker 在 Docker 镜像层内预览文件 现在可以在 Services&#xff08;服务&#xff09;工具窗口中轻松访问和预览 Docker 镜像层的内容。 从列表选择镜像&#xff0c;选择 Show layers&#xff08;显示层&#xff09;&#xff0c;然后点击 Analyze image for more informati…

平价开放式耳机怎么选?盘点几款好用的平价开放式耳机!

在这个充满音频奇迹的年代&#xff0c;选一副好耳机就像是挑选人生伴侣一样重要&#xff0c;而开放式耳机&#xff0c;由于佩戴无需入耳带来了不错的舒适度&#xff0c;就此受到了许多人的喜爱。 可问题是&#xff0c;市面上平价开放式耳机太多&#xff0c;让人眼花缭乱&#…

医院运维 告警闪现后的故障排查

长期以来&#xff0c;医院信息化运维中存在着科室复杂、应用场景多、终端运维工作量大、软件系统兼容需求强等诸多痛点&#xff0c;且对技术设备的稳定性、连续性要求极高&#xff0c;在日常运维中&#xff0c;需要应对和解决这些问题来保障业务稳定、健康运行。 1、数据孤岛 …

【离散数学】——期末刷题题库(二元关系作业一(运算性质闭包))

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

揭秘MQTT:为何它是物联网的首选协议?

文章目录 MQTT 协议简介概览MQTT 与其他协议对比MQTT vs HTTPMQTT vs XMPP 为什么 MQTT 是适用于物联网的最佳协议&#xff1f;轻量高效&#xff0c;节省带宽可靠的消息传递海量连接支持安全的双向通信在线状态感知 MQTT 5.0 与 3.1.1MQTT 服务器MQTT 客户端 MQTT 协议简介 概…

acwing1209.带分数暴力与优化(java版)

//n a b / c n是确定的,只需找到其中两个。判断剩下一个数是否满足条件即可 //由题目条件可知,每个数不能重复使用,需要一个st全局数组判断每个数是否使用过 //递归实现排列型枚举,cn ac b //对于枚举出来的每一个a,再去枚举每一个c,再在c的枚举里判断b是否满足条件 //…

第四期丨酷雷曼无人机技能培训

第4期无人机技能培训 2023年10月25日&#xff0c;酷雷曼无人机技能培训及执照考试第四期成功举办&#xff0c;自7月份首期开办以来&#xff0c;已按照每月一期的惯例连续举办四期&#xff0c;取得了极为热烈的反响。 随着无人机培训的重要性及影响力逐渐扩大&#xff0c;参加培…

算法-贪心思想

贪心的思想非常不好解释&#xff0c;而且越使用权威的语言解释越难懂。而且做题的时候根据自己的理解可能直接做出来&#xff0c;但是非要解释一下怎么使用的贪心的话&#xff0c;就懵圈了。一般来说&#xff0c;贪心的题目没有固定的套路&#xff0c;一题一样&#xff0c;不过…

分享67个节日PPT,总有一款适合您

分享67个节日PPT&#xff0c;总有一款适合您 67个节日PPT下载链接&#xff1a;https://pan.baidu.com/s/1oU-UUCV_69e8Gp5Y6zrzVA?pwd6666 提取码&#xff1a;6666 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易…

Spark---Spark on Hive

1、Spark On Hive的配置 1&#xff09;、在Spark客户端配置Hive On Spark 在Spark客户端安装包下spark-2.3.1/conf中创建文件hive-site.xml&#xff1a; 配置hive的metastore路径 <configuration><property><name>hive.metastore.uris</name><v…

关于对ArrayBlockingQueue 的AQS探究

1、介绍 条件队列是 AQS 中最容易被忽视的一个细节。大部分时候&#xff0c;我们都用不上条件队列&#xff0c;但是这并不说明条件队列就没有用处了&#xff0c;它反而是我们学习生产者-消费者模式的最佳教材。条件队列是指一个阻塞队列&#xff0c;其中的元素是等待某个条件成…

每日一题:LeetCode-75. 颜色分类

每日一题系列&#xff08;day 12&#xff09; 前言&#xff1a; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f50e…

ROS 元功能包

ROS元功能包&#xff08;Metapackage&#xff09;是一种特殊的软件包&#xff0c;它本身并不包含任何可执行代码或数据文件。在ROS 1中&#xff0c;可以通过catkin_create_pkg命令创建元功能包。 相反&#xff0c;它的主要目的是作为一组相关功能包的集合或者依赖关系列表。使…

蓝桥杯每日一题2023.12.5

题目描述 1.一步之遥 - 蓝桥云课 (lanqiao.cn) 题目分析 对于本题遵循多了就减少了就加的原则&#xff0c;用while进行计算即可 #include<bits/stdc.h> using namespace std; int x, ans; int main() {while(x ! 1){if(x < 1)x 97;else x - 127;ans ;}cout <&…

vue-cli创建项目运行报错this[kHandle] = new _Hash(algorithm, xofLen);(完美解决)

1&#xff1a;问题出现的原因 出现这个问题是node.js 的版本问题&#xff0c;因为 node.js V17开始版本中发布的是OpenSSL3.0, 而OpenSSL3.0对允许算法和密钥大小增加了严格的限制&#xff0c;可能会对生态系统造成一些影响。故此以前的项目在使用 nodejs V17以上版本后会报错。…

使用VBA快速统计词组(单词组合)词频

实例需求&#xff1a;产品清单如A列所示&#xff0c;现在如下统计词组词频。想必各位小伙伴都指定如何使用字典对象实现去重&#xff0c;进而实现单个单词的词频统计。 但是统计词组词频就没有那么简单了&#xff0c;为了便于演示&#xff0c;此处的词组只限于两个单词的组合。…

阿里云Arthas使用——在日志没有输出异常情况下,如何进行线上bug定位 stack命令 和 trace命令

前言 Arthas 是一款线上监控诊断产品&#xff0c;通过全局视角实时查看应用 load、内存、gc、线程的状态信息&#xff0c;并能在不修改应用代码的情况下&#xff0c;对业务问题进行诊断&#xff0c;包括查看方法调用的出入参、异常&#xff0c;监测方法执行耗时&#xff0c;类…

深入理解:指针变量的解引用 与 加法运算

前言 指针变量的解引用和加法运算是非常高频的考点&#xff0c;也是难点&#xff0c;因为对初学者的不友好&#xff0c;这就导致了各大考试都很喜欢在这里出题&#xff0c;通常会伴随着强制类型转换、二维数组、数组指针等一起考查大家对指针的理解。但是不要怕&#xff0c;也许…

托盘四向穿梭车自动化密集库供应|单机智能向系统智能跨越的HEGERLS托盘四向车系统

随着物流产业的迅猛发展&#xff0c;托盘四向穿梭式自动化密集仓储系统可认为是在穿梭车货架系统基础上提出的一种新仓储概念。托盘四向穿梭式立体库因其在流通仓储体系中所具有的高效密集存储功能优势、运作成本优势与系统化智能化管理优势&#xff0c;已发展为仓储物流的主流…
最新文章