JavaEE-线程进阶

news2025/1/12 20:56:05

在这里插入图片描述在这里插入图片描述
在这里插入图片描述


模拟实现一个定时器
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
运行结果如下:
在这里插入图片描述
上述模拟定时器的全部代码:

import java.util.PriorityQueue;

//创建一个类,用来描述定时器中的一个任务
class MyTimerTask implements Comparable<MyTimerTask> {
    //任务执行时间
    private long time;
    //具体任务
    private Runnable runnable;

    //构造函数
    public MyTimerTask(Runnable runnable,long delay) {
        this.time = System.currentTimeMillis()+delay;
        this.runnable = runnable;
    }
    public long getTime() {
        return time;
    }
    public Runnable getRunnable() {
        return runnable;
    }

    @Override
    public int compareTo(MyTimerTask o) {
        //时间小的任务,会被放置在队首
        return (int)(this.time-o.time);
    }
}

//定时器类的本体
class MyTimer{
    //创建一个优先级队列存储上述的N个任务
    private PriorityQueue<MyTimerTask> queue=new PriorityQueue<>();

    //用来加锁的对象
    private Object locker=new Object();

    //提供一个schedule方法,把要执行的任务添加到队列中去
    public void  schedule(Runnable runnable,long delay){
        //new 一个任务对象
        synchronized (locker){
            MyTimerTask task=new MyTimerTask(runnable,delay);
            queue.offer(task);
            //每次来新的任务,都唤醒之前的扫描线程,让扫描线程根据当前的任务情况,重新规划等待时间
            locker.notify();
        }
    }
    //构造函数 提供一个扫描线程,一方面去监控队首元素是否到执行时间了,另一方面,如果到了执行时间,这需要调用这里的Runable中的run方法来完成任务
    public MyTimer(){
        Thread t=new Thread(() ->{
           while(true){
               try {
                   synchronized (locker){
                       while(queue.isEmpty()){
                           //如果当前队列为空,就不应该去队列中取任务,使用wait进行等待,直到有任务加入队列
                           locker.wait();
                       }
                       //判断当前队列中的队首元素距离执行时间的时间差
                       MyTimerTask task=queue.peek();
                       long curTime=System.currentTimeMillis();
                       if(curTime>=task.getTime()){
                           //当前时间大于等于任务的执行时间,开始执行
                           queue.poll();//把已经执行的任务弹出队列
                           task.getRunnable().run();//执行任务
                       }else{
                           //没有到任务时间,扫描线程休眠时间差
                           //Thread.sleep(task.getTime()-curTime);
                           locker.wait(task.getTime()-curTime);
                       }
                   }
                   }catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        });
        t.start();
    }

}

public class Demo21 {
    public static void main(String[] args) {
        MyTimer timer=new MyTimer();
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 3");
            }
        },3000);

        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 2");
            }
        },2000);

        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 1");
            }
        },1000);
        System.out.println("程序开始运行");
    }
}


线程池
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


模拟实现一个线程池
只需要提交任务给线程池即可
核心操作为 submit, 将任务加入线程池中
使用一个 BlockingQueue 组织所有的任务

代码如下:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

//模拟实现一个线程池
class MyThreadPool{
    //将添加到线程池中的任务可以放置到这个队列中
    private BlockingQueue<Runnable> queue =new LinkedBlockingQueue<>();
    //通过这个方法可以将任务添加到线程池中
    public void  submit(Runnable runnable) throws InterruptedException {
        queue.put(runnable);
    }
    //构造函数,创建一个线程池,数量为n
    public  MyThreadPool(int n){
        for (int i = 0; i <n; i++) {
            Thread t=new Thread(() ->{
               while(true){
                   try {
                       //取放入线程池队列中的任务进行执行
                       Runnable runnable= queue.take();
                       runnable.run();
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
               }
            });
            t.start();
        }
    }

}
public class Demo23 {
    public static void main(String[] args) throws InterruptedException {
    MyThreadPool myThreadPool=new MyThreadPool(4);
        for (int i = 0; i <10; i++) {
            myThreadPool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(
                            Thread.currentThread().getName()+"hello"
                    );
                }
            });
        }
    }
}

执行结果如下:

在这里插入图片描述

在这里插入图片描述


进阶内容


在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


在这里插入图片描述
上述第二种情况的案例,如下
在这里插入图片描述
结果如下:
在这里插入图片描述
上述过程的所有代码:

//死锁
public class Demo24 {
    private  static  Object locker1=new Object();
    private  static  Object locker2=new Object();
    public static void main(String[] args) {
        Thread t1=new Thread(() ->{
            synchronized (locker1) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (locker2){
                    System.out.println("t1 两把锁加锁成功");
                }
            }

        });

        Thread t2=new Thread(() ->{
            synchronized (locker2) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (locker1){
                    System.out.println("t2 两把锁加锁成功");
                }
            }

        });

        t1.start();
        t2.start();
    }
}


我们可以通过jconsole来观察线程的执行过程
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


在这里插入图片描述在这里插入图片描述
在这里插入图片描述


在这里插入图片描述
在这里插入图片描述


在这里插入图片描述
在这里插入图片描述
利用原子类实现线程安全
在这里插入图片描述
上述的代码如下:

import java.util.concurrent.atomic.AtomicInteger;

//利用原子类实现线程安全
public class Demo25 {
    private static AtomicInteger count=new AtomicInteger(0);
    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(() -> {
            for (int i = 0; i <5000; i++) {
                count.getAndIncrement();//后置++

            }
        });
        Thread t2=new Thread(() -> {
            for (int i = 0; i <5000; i++) {
                count.getAndIncrement();//后置++

            }
        });
        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println(count.get());
    }
}


在这里插入图片描述

在这里插入图片描述


*加粗样式**


在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


在这里插入图片描述
下面利用Callable建立一个线程
在这里插入图片描述
上述过程的代码如下:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
//利用Callable建立一个线程
public class Demo26 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Integer> callable =new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum=0;
                for (int i = 0; i <1000; i++) {
                    sum+=i;
                }
                return sum;
            }
        };
        //callable不能直接用,需要借用FutureTask这个标签
        FutureTask<Integer> futureTask=new FutureTask<>(callable);
        Thread t =new Thread(futureTask);
        t.start();

        System.out.println(futureTask.get());
    }
}

在这里插入图片描述


在这里插入图片描述
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述
在这里插入图片描述
下面简单使用一下这个信号量
在这里插入图片描述
上述过程的完整代码如下:

import java.util.concurrent.Semaphore;
//Semaphore  信号量
public class Demo27 {
    public static void main(String[] args) throws InterruptedException {
        //指定计数器的初始值
        Semaphore semaphore=new Semaphore(4);
        semaphore.acquire();
        System.out.println("执行了一次P操作");
        semaphore.acquire();
        System.out.println("执行了一次P操作");
        semaphore.acquire();
        System.out.println("执行了一次P操作");
        semaphore.acquire();
        System.out.println("执行了一次P操作");
        semaphore.acquire();
        System.out.println("执行了一次P操作");
    }
}


在这里插入图片描述同时等待 N 个任务执行结束.
在这里插入图片描述
上述过程的完整代码如下:

import java.util.concurrent.CountDownLatch;
//使用CountDownLatch将任务分配给多个线程来完成
public class Demo28 {
    public static void main(String[] args) throws InterruptedException {
        //指定创建任务的数量
        CountDownLatch countDownLatch=new CountDownLatch(10);
        for (int i = 0; i <10; i++) {
            int id=i;
            Thread t=new Thread(() ->{
                System.out.println( id + "开始工作");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println( id + "结束工作");
                // 每个任务执行结束这里, 调用一下方法,记录该线程是否结束
                // 把 10 个线程想象成短跑比赛的 10 个运动员. countDown 就是运动员撞线了.
                countDownLatch.countDown();
            });
            t.start();
        }
        // 主线程中可以使用 countDownLatch 负责等待任务结束.
        // a => all 等待所有任务结束. 当调用 countDown 次数 < 初始设置的次数, await 就会阻塞.
        countDownLatch.await();
        System.out.println("所有任务执行完毕");
    }
}

在这里插入图片描述


在这里插入图片描述
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


在这里插入图片描述


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据分析视角中的商业分析学习笔记

数据分析一大堆&#xff0c;结果却是大家早就知道的结论&#xff1f;是工具和方法出问题了吗&#xff1f;真正原因可能是你的思维有误区。 为什么分析的这么辛苦&#xff0c;得出的结论大家早知道&#xff0c;谁谁都不满意&#xff1f;核心原因有3个&#xff1a; 分析之前&am…

DHCPsnooping 配置实验(2)

DHCP报文泛洪攻击 限制接收到报文的速率 vlan 视图或者接口视图 dhcp request/ dhcp-rate dhcp snooping check dhcp-request enable dhcp snooping alarm dhcp-request enable dhcp snooping alarm dhcp-request threshold 1 超过则丢弃报文 查看[Huawei]dis dhcp statistic…

使用python-opencv检测图片中的人像

最简单的方法进行图片中的人像检测 使用python-opencv配合yolov3模型进行图片中的人像检测 1、安装python-opencv、numpy pip install opencv-python pip install numpy 2、下载yolo模型文件和配置文件&#xff1a; 下载地址&#xff1a; https://download.csdn.net/down…

如何使用 AI与人工智能的定义、研究价值、发展阶段

目录 一、什么是人工智能 二、人工智能的研究价值 三、人工智能的发展阶段 一、什么是人工智能 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是一门研究如何使计算机能够模拟和执行人类智能活动的科学与技术。人工智能旨在开发智能代理&…

CLIP 论文逐段精读【论文精读】

00:06评价&#xfeff; 评价&#xff1a;工作clip呢自从去年2月底提出就立马火爆全场&#xff0c;他的方法出奇的简单&#xff0c;但是效果呢又出奇的好&#xff0c;很多结果和结论呢都让人瞠目结舌。比如呢作者说clip的这个迁移学习能力是非常强的&#xff0c;它预训好的这个模…

【C语言】利用数组处理批量数据(一维数组和二维数组)

前言:在前面学习的程序中使用的变量都属于基本类型&#xff0c;例如整型、字符型、浮点型数据&#xff0c;这些都是简单的数据类型。对于简单的问题&#xff0c;使用这些简单的数据类型就可以了。但是对于有些需要处理的数据&#xff0c;只用以上简单的数据类型是不够的&#x…

Obsidian插件推荐_231005

起因 十一在家整理 OB 笔记&#xff0c;发现两个超好用的插件&#xff1a;Linter & tag wrangler。 前一阵把 Obsidian 笔记用 Hexo 转换成静态网页发到 github.io 做自己 blog 网站。发现了笔记中的一些问题&#xff0c;比如 tag 过多、重复&#xff0c;markdown 格式不…

菲律宾电商市场潜力巨大,Temu迎来东南亚扩张良机!(测评补单)

从拼多多传出筹备出海扩张的消息以来&#xff0c;业界都认定其迟早要进军东南亚市场。在7月份Temu上线日本站后可以看出Temu这条扩张路线背后的商业逻辑是先占领高购买力国&#xff0c;再向中低购买力国扩张&#xff0c;所以亚洲首站选择了高购买力的日本。果然在完成日韩布局后…

零基础入门初学 Python 需要安装哪些软件?

Python是近年来备受热门的编程语言&#xff0c;其简明易读、开源免费、跨平台等特点&#xff0c;使得Python倍受喜爱&#xff0c;成为初学者及开发者心中的首选。 如果你是第一次接触Python&#xff0c;又不想繁琐地安装各种软件&#xff0c;可以尝试在线运行Python代码&#…

【RCRL充放电时间相关计算】

一. 基础知识 L、C元件称为“惯性元件”&#xff0c;即电感中的电流、电容器两端的电压&#xff0c;都有一定的“电惯性”&#xff0c;不能突然变化。充放电时间&#xff0c;不光与L、C的容量有关&#xff0c;还与充/放电电路中的电阻R有关。RC电路的时间常数&#xff1a;τRC…

【扩散模型】 DDPM和DDIM讲解

扩散模型DDPM和DDIM 扩散模型之DDPM介绍了经典扩散模型DDPM的原理和实现&#xff0c;那么生成一个样本的次数和训练次数需要一致&#xff0c;导致采样过程很缓慢。这篇文章我们将介绍另外一种扩散模型DDIM&#xff08;Denoising Diffusion Implicit Models&#xff09;&#x…

STM32CubeMX学习笔记-DAC接口使用(输出电压)

STM32CubeMX学习笔记-DAC接口使用&#xff08;输出电压&#xff09; 一、DAC简介二、DAC通道选择三、新建工程四、DAC14.1 参数配置4.2 生成代码 五、库函数六、修改main函数 原创链接 1 一、DAC简介 DAC(Digital-to-Analog Converter)&#xff0c;即数字/模拟转换模块&#x…

番外--常用文件目录类命令

------------- task00: 00&#xff1a;常用文件目录类命令1-18.&#xff08;pwd&#xff1b; cd&#xff1b;ls&#xff1b; more&#xff1b;less&#xff1b;head&#xff1b;tail&#xff1b; mkdir&#xff1b;rmdir&#xff1b;cp&#xff1b;mv&#xff1b;rm&#xff1b…

第八章 排序 三、希尔排序

目录 一、算法思想 二、例子 三、代码实现 五、验证 六、空间复杂度 七、时间复杂度 八、稳定性 一、算法思想 先追求表中元素部分有序&#xff0c;在逐渐逼近表中元素全部有序。 二、例子 1、我们要升序排列此表 2、取一个差值作为子表的划分的条件&#xff0c;希尔本…

SSM - Springboot - MyBatis-Plus 全栈体系(十九)

第四章 SpringMVC 二、SpringMVC 接收数据 1. 访问路径设置 RequestMapping 注解的作用就是将请求的 URL 地址和处理请求的方式&#xff08;handler 方法&#xff09;关联起来&#xff0c;建立映射关系。SpringMVC 接收到指定的请求&#xff0c;就会来找到在映射关系中对应的…

CTFHUB - SSRF

目录 SSRF漏洞 攻击对象 攻击形式 产生漏洞的函数 file_get_contents() fsockopen() curl_exec() 提高危害 利用的伪协议 file dict gopher 内网访问 伪协议读取文件 端口扫描 POST请求 总结 上传文件 总结 FastCGI协议 CGI和FastCGI的区别 FastCGI协议 …

盒子阴影和网页布局

盒子阴影 box-shadow: 10px 10px 10px 4px rgba(0,0,0,.3);//最后一个是透明度 传统网页布局的三种方式 标准流 就是按照规定好的默认方式排列 1.块级元素&#xff1a;div、hr、p、h1~h2、ul、ol、dl、form、table 行内元素会按照书顺序&#xff0c;从左到右顺序排列&#…

1.2 数据模型

思维导图&#xff1a; 前言&#xff1a; **1.2.1 什么是模型** - **定义**&#xff1a;模型是对现实世界中某个对象特征的模拟和抽象。例如&#xff0c;一张地图、建筑设计沙盘或精致的航模飞机都可以视为具体的模型。 - **具体模型与现实生活**&#xff1a;具体模型可以很容…

剑指offer——JZ55 二叉树的深度 解题思路与具体代码【C++】

一、题目描述与要求 二叉树的深度_牛客题霸_牛客网 (nowcoder.com) 题目描述 输入一棵二叉树&#xff0c;求该树的深度。从根结点到叶结点依次经过的结点&#xff08;含根、叶结点&#xff09;形成树的一条路径&#xff0c;最长路径的长度为树的深度&#xff0c;根节点的深度…

【简单了解一下红黑树】

文章目录 红黑树1.简介2.为什么需要红黑树&#xff1f;3.性质4. 红黑树的效率4.1 红黑树效率4.2 红黑树和AVL树的比较 5.AVL树 vs 红黑树5.1 AVL树5.2 红黑树5.3 如何选择 红黑树 1.简介 红黑树是一种自平衡的二叉查找树&#xff0c;是一种高效的查找树。它是由 Rudolf Bayer …