华杉研发九学习日记24 线程同步 死锁 线程通信 线程池 Callable接口

news2024/9/23 17:20:01

华杉研发九学习日记24

java多线程

一,线程同步

1.1 线程同步问题

多个线程同时操作一个全局数据或静态数据时可能会造成数据冲突

解决:

  • synchronized同步代码块
  • synchronized同步方法
  • 使用锁对象加锁解锁
//  火车站卖车票  --  100张
public class Train implements Runnable{
    int count = 100;    //一百张火车票,全局变量
    private boolean flag = true;
    @Override
    public void run() {
        while(flag){    //  永久开启窗口售卖火车票
            sale();
        }
    }
    public void sale(){
        //  设置一个停止售卖的条件
        if(count<=0){
            flag = false;
            return;
        }
        System.out.println(Thread.currentThread().getName()+ "窗口售出了第"+count+"张火车票!");
        count--;
    }
}
public class TestTrain {
    public static void main(String[] args) {
        //  创建火车票对象
        Train train = new Train();
        //  启动线程
        new Thread(train,"窗口一").start();
        new Thread(train,"窗口二").start();
        new Thread(train,"窗口三").start();
    }
}
//	测试结果卖出票会出现重复和顺序混乱等问题

1.2 同步代码块

Java中采用锁来保护共享资源,防止数据不一致的情况产生。下面我们就来介绍Java中的同步机制以及synchronized关键字。

在Java中,每个对象都拥有一个"互斥锁标记",这就好比是我们说的挂锁。这个锁标记,可以用来分给不同的线程。之所以说这个锁标记是"互斥的",因为这个锁标记同时只能分配给一个线程。

光有锁标记还不行,还要利用synchronized 关键字进行加锁的操作。

synchronized 关键字有两种用法

第一种: synchronized+代码块。

synchronized(obj){

	代码块;

}

synchronized关键字后面跟一个圆括号,括号中的是某一个引用,这个引用应当指向某一个对象。后面紧跟一个代码块,这个代码块被称为同步代码块""。
这种语法的含义是,如果某一个线程想要执行代码块中的代码,必须要先获得obj所指向对象的互斥锁标记。也就是说,如果有一个线程t1要想进入同步代码块,必须要获得obj对象的锁标记;而如果t1线程正在同步代码块中运行,这意味着t1有着obj对象的互斥锁标记;而这个时候如果有一个t2线程想要访问同步代码块,会因为拿不到obj 对象的锁标记而无法继续运行下去。

public void sale(){
    synchronized (object){//  设置一个停止售卖的条件
        if (count <= 0) {
            flag = false;
            return;
        }
        System.out.println(Thread.currentThread().getName() + "窗口售出了第" + count + "张火车票!");
        count--;
    }
}

1.3 同步方法

public synchronized void sale(){
    if (count <= 0) {
            flag = false;
            return;
        }
        System.out.println(Thread.currentThread().getName() + "窗口售出了第" + count + "张火车票!");
        count--;
}

1.4 使用锁对象

    private Lock lock = new ReentrantLock();//	创建锁对象
//  使用锁对象上锁
public void sale(){
    lock.lock();    //  上锁
    if (count <= 0) {
        flag = false;
        lock.unlock();  //  解锁
        return;
    }
    System.out.println(Thread.currentThread().getName() + "窗口售出了第" + count + "张火车票!");
    count--;
    lock.unlock();  //  解锁
}

二,死锁

如果同步代码块包裹多层时,可能会产生新的问题

(a等待b释放,b等待a释放)

synchronized(a){
    synchronized(b){
        代码块;
    }
}
synchronized(b){
    synchronized(a){
        代码块;
    }
}

解决死锁:

在Java中。采用了wait和notify这两个方法,来解决死锁机制。
首先,在Java中,每一个对象都有两个方法: wait和notify方法。这两个方法是定义在Object类中的方法。对某个对象调用wait(方法,表明让线程暂时释放该对象的锁标记。

synchronized(a){
    a.wait();
    synchronized(b){
        代码块;
    }
}
synchronized(b){
    synchronized(a){
        代码块;
        a.notify();
    }
}

在这里插入图片描述

由于可能有多个线程先后调用a对象 wait方法,因此在a对象等待状态中的线程可能有多个。而调用a.notify()方法,会从a对象等待状态中的多个线程里挑选一个线程进行唤醒。与之对应的,有一个notifyAll)方法,调用a.notifyAll会把a对象等待状态中的所有线程都唤醒。

wait作用是让当前线程阻塞,阻塞多久,取决于有没有其他线程唤醒它。notify作用是唤醒处于wait状态的线程。必须是同一个监视器下的线程。
notifyAll作用是唤醒所有处于wait状态的线程。必须是同一个监视器下的线程。

三,线程通信

不同线程之间可以相互的发信号。这就是线程通信。之所以需要进行线程通信,是因为有些时候,一个线程的执行需要依赖另外一个线程的执行结果。在结果到来之前,让线程等待(wait),有了结果只之后再进行后续的操作。对于另外一个线程而言,计算完结果,通知(notify)一下处于等待状态的线程.

线程通信借助的是Object类的wait,notify,notifyAll方法。

wait作用是让当前线程阻塞,阻塞多久,取决于有没有其他线程唤醒它。

notify作用是唤醒处于wait状态的线程。必须是同一个监视器下的线程。

notifyAll作用是唤醒所有处于wait状态的线程。必须是同一个监视器下的线程。

一般情况下,多线程里会出现线程同步的问题,我们不但要进行线程通信,还要解决线程同步的问题。

wait 与notify应用:生产者-消费者模式
这是一个比较经典的多线程场景。有商品的时候,消费者才可以消费,没有商品的时候,消费者等待。商品库存充足的时候,生产者等待,库存不满的时候,生产者生产商品。

四,线程池

什么是线程池?

水池:存放水的池子。线程池:存放线程的池子。

Java中的线程池:是一个管理线程的池子。可以在需要的时候开辟线程,可以控制最大开辟的线程个数,可以在不需要的时候关闭线程,可以让任务排队执行。这些管理过程不需要我们干预,线程池能帮我们完成。我们所要做的就是往线程池中放任务。
为什么要有线程池?

多线程解决了任务并发问题,但是开辟和关闭线程很消耗系统的性能,开辟和关闭一个线程要处理很多细节,频繁的开辟和关闭线程会给系统增加很多开销。

线程池使用了重用的概念,可以控制线程开辟的数量,复用这些线程执行任务。这样就不用频繁的开辟和关闭线程了。

线程池使用场景及优势
线程池适合处理的任务:执行时间短、工作内容较为单一。

合理使用线程池带来的好处:
1)降低资源消耗:重复利用已创建的线程降低线程创建和销毁造成的开销

​ 2)提高响应速度:当任务到达时。任务可以不用等待线程创建就能立即执行

​ 3)提高线程的可管理性:可以统一对线程进行分配、调优和监控

​ 4)提供更多强大的功能:线程池具备可拓展性,允许开发人员向其中增加更多的功能。比如延时定时线程池SchedulerThreadPoolExecutor,允许任务延期执行或定期执行

线程池的作用包括:
1):利用线程池管理并复用线程、控制最大并发数等

​ 2):实现任务线程队列缓存策略和拒绝机制

​ 3):实现某些与时间相关的功能。如定时执行、周期执行

​ 4)∶隔离线程环境。通过配置两个或多个线程池,将一台服务器上较慢的服务和其他服务隔离开,避免各服务线程相互影响。

三种常见的线程池

  • 固定线程个数的线程池
  • 不限线程个数的线程池
  • 单个线程的线程池(串行任务池)
public static void main(String[] args) {
    //  创建线程池
    ExecutorService es = Executors.newFixedThreadPool(2);
    //  提交任务    --  把任务提交给线程池,让其从线程池中获取一个线程,并执行其当前任务
    es.submit(new Runnable() {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"你好");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    });
    es.submit(new Runnable() {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"哟西");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    });
    es.submit(new Runnable() {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"你好");
        }
    });
    //  关闭资源
    es.shutdown();
}

拷贝:

public class TestCopy {
    public static void main(String[] args) {
        //  1.创建线程池
        ExecutorService es = Executors.newFixedThreadPool(3);
        //  2.找到其文件夹遍历其中的文件。如果是文件,则把拷贝的任务提交给战程法
        File file = new File("C:\\Users\\86155\\Videos\\Counter-strike 2");
        File[] files = file.listFiles();
        for (File f : files) {
            if (f.isFile()) {
                //  把拷贝的任务交给线程池
                es.submit(new Runnable() {
                    @Override
                    public void run() {
                        try(BufferedInputStream fis = new BufferedInputStream(new FileInputStream(f));
                            BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\86155\\Desktop\\张晓岚\\aa\\"+f.getName()))
                        ) {
                            byte[] buffer = new byte[1024];
                            int len;
                            while ((len = fis.read(buffer)) != -1) {
                                fos.write(buffer, 0, len);
                            }

                        } catch (FileNotFoundException e) {
                            throw new RuntimeException(e);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    }
                });
            }
        }
        es.shutdown();

    }
}

五,Callable接口

创建步骤;
1.创建一个子类,实现Callable接口

​ 2.重写其中的call方法

​ 3.创建EgtrueTask对象,封装Callable对象

​ 4.创建Thread对象,封装FutureTask对象

​ 5.使用start来启动线程

public class MyCall implements Callable {
    @Override
    public Object call() throws Exception {
        for (int i = 0; i < 100; i++) {
            System.out.println("------"+i);
        }
        return 100;
    }
}
public class TestMyCall {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //  实现Callable接口方式
        MyCall myCall = new MyCall();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(myCall);
        new Thread(futureTask).start();
        System.out.println(futureTask.get());// 打印线程执行后返回的结果数据

        //  主线程
        for (int i = 0; i < 100; i++) {
            System.out.println("====="+i);
        }
    }
}

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

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

相关文章

Django ASGI服务

1. ASGI简介 在Django中, ASGI(Asynchronous Server Gateway Interface)的引入使得Django应用能够支持异步编程. 从Django 3.0开始, Django就增加了对ASGI的支持, 但直到Django 3.1才正式推荐在生产环境中使用ASGI. ASGI是一个用于Python的异步Web服务器的标准接口, 它允许你运…

图解RocketMQ之消息如何存储

大家好&#xff0c;我是苍何。 人一辈子最值得炫耀的不应该是你的财富有多少&#xff08;虽然这话说得有点违心&#xff0c;呵呵&#xff09;&#xff0c;而是你的学习能力。技术更新迭代的速度非常快&#xff0c;那作为程序员&#xff0c;我们就应该拥有一颗拥抱变化的心&…

西安交通大学先进动力与新能源发展峰会举行

8月3日&#xff0c;西安交通大学第十届先进动力与新能源发展峰会暨西安交大先进动力校友会2024年年会在深圳举行。西安交通大学党委常委、副校长单智伟&#xff0c;南方科技大学清洁能源研究院院长、创新创业学院院长、澳大利亚国家工程院外籍院士刘科&#xff0c;西安交通大学…

抑制电机噪声的又一神器 -- 三线共模电感

概述 针对电机产品&#xff0c;尤其是三相无刷电机&#xff0c;如图1&#xff0c;其噪声源主要是电机的开关驱动模块&#xff08;具体可参阅另一篇文章“”&#xff09;&#xff0c;而一般的等效天线即为连接电机与驱动板的电机线&#xff08;等效天线、四分之一波长的理论解释…

R18 NTN中的Satellite switch with re-sync过程

更多精彩内容,请阅知识星球合集链接。该链接收录了目前知识星球所有内容,涵盖了5G相关领域的绝大多数知识点;主要以协议原文截图后进行解释讲解外加实网log对照为主,辅以星友问答等等精华内容。 合集链接如下(不用登录飞书即可查看):Docs 如果您对3GPP spec阅读有困扰; 如…

HTTPS 比 HTTP 更安全吗?这两种协议有什么区别?

在互联网的通讯过程中&#xff0c;HTTP&#xff08;超文本传输协议&#xff09;和HTTPS&#xff08;安全HTTP&#xff09;是两种最基本、最重要的通讯协议&#xff0c;它们在网络中都扮演着重要的角色。然而近年来&#xff0c;随着网络安全问题的日益突出&#xff0c;HTTPS的安…

测试人员怎么通过浏览器开发工具 Performance 分析性能

在现代Web开发中&#xff0c;性能优化是一个永恒的话题。对于测试人员来说&#xff0c;如何有效地使用浏览器开发工具中的Performance面板&#xff0c;进行性能分析和调优&#xff0c;是一项必备技能。本文将带你深入了解浏览器开发工具Performance面板的使用方法及其在性能测试…

OrangePi AIpro学习2 —— 配置昇腾DVPP环境

目录 一、clone需要运行的软件 二、运行corp程序 2.1 解决缺少sample_common.sh 2.2 解决缺少INSTALL_DIR环境变量 2.3 运行程序 三、测试其他程序 3.1 程序目录 3.2 程序注意事项 3.3 如何找出报错原因 一、clone需要运行的软件 1. 软件地址 samples: CANN Samples…

Docker 设置代理

Docker 设置代理 创建配置文件 sudo mkdir -p /etc/systemd/system/docker.service.d sudo touch /etc/systemd/system/docker.service.d/proxy.conf sudo vim /etc/systemd/system/docker.service.d/proxy.conf 编辑代理配置 #输入以下内容&#xff0c;其中代理改成自己的…

【大小球让球实战】——深度剖析足球大小球数据分析软件,找到一个临界点,把准确率提高到70%?

最近在跟一些圈内朋友聊天&#xff0c;发现每个人都有一套自己的玩球逻辑&#xff0c;比如有些人看亚盘&#xff0c;有些看欧盘&#xff0c;有些玩绝杀&#xff0c;有些看盘口&#xff0c;是否可以自定义的去玩球&#xff1f;结合多年的经验&#xff0c;把分析的过程大概写了一…

ESP32在ESP-IDF环境下禁用看门狗

最近使用了一款ESP32的开发板。但在调试时发现出现许多看门狗复位事件&#xff1a; E (8296) task_wdt: Task watchdog got triggered. The following tasks/users did not reset the watchdog in time: E (8296) task_wdt: - IDLE (CPU 0) E (8296) task_wdt: Tasks curre…

FFmpeg 7.0重大更新

0、维护工作 对于任何成熟的软件&#xff0c;每个版本必然包含大量的bugfix、cleanup。维护工作不会出现在Changelog中&#xff0c;不是吸引眼球的东西&#xff0c;但是人力投入的占比最高&#xff0c;是一个项目长期稳定的保证。 维护工作必须得提两个人&#xff0c;Andreas…

校园超市收银软件的挑战:双系统困境-亿发

在现代零售业中&#xff0c;高效的管理系统是确保业务顺利进行的关键。然而&#xff0c;对于学校直属管理的超市来说&#xff0c;选择合适的收银系统往往是一项挑战。由于缺乏能够同时满足收银和进销存管理需求的高适配性系统&#xff0c;许多学校超市不得不同时使用两套系统&a…

iPhone手机清理软件:让你的设备焕然一新

随着智能手机在我们生活中的地位日益重要&#xff0c;保持设备的最佳性能就显得尤为关键。对于iPhone用户而言&#xff0c;随着时间的推移&#xff0c;手机可能会因累积了过多的缓存文件、重复照片、未使用的应用和各种其他数据而变得缓慢。幸运的是&#xff0c;市面上有多种iP…

可以翻页、互动、留言和弹幕的仿真电子相册制作方法

​在数字化时代&#xff0c;仿真电子相册作为一种结合了翻页、互动、留言和弹幕等多种功能的创意表达形式&#xff0c;正逐渐成为人们记录生活和分享回忆的重要方式。本教程将介绍如何利用FLBOOK这款强大的电子相册制作工具&#xff0c;制作具有这些特性的令人印象深刻的作品。…

ICM-20948芯片详解(6)

接前一篇文章&#xff1a;ICM-20948芯片详解&#xff08;5&#xff09; 五、组件概览及详述 再次给出ICM-20948芯片的内部结构框图&#xff1a; 2. 组件详述 &#xff08;6&#xff09;辅助I2C串行接口 ICM-20948具有用于与外部传感器通信的辅助I2C总线。该总线有两种操作模…

实时采集同花顺要闻直播资讯

采集同花顺要闻直播资讯能实时掌握市场动态、政策变化及企业新闻&#xff0c;对投资者而言&#xff0c;有助于及时做出投资决策&#xff0c;把握市场机会&#xff0c;规避风险。对于研究机构和媒体&#xff0c;它提供一手资料&#xff0c;支持深度分析与报道。 采集网址&#x…

第 8 章 虚拟文件系统(7)

目录 8.5 标准函数 8.5.1 通用读取例程 8.5.2 失效机制 8.5.3 权限检查 8.6 小结 本专栏文章将有70篇左右&#xff0c;欢迎关注&#xff0c;查看后续文章。 8.5 标准函数 大多数文件系统中 file_operations 的 read&#xff0c;write 分别为&#xff1a; do_sync_read&am…

Android开发之事件分发

#来自ウルトラマンゼロ&#xff08;哉阿斯&#xff09; 1 Activity 构成 平常布局展示在ContentView中。 2 事件分发 事件分发的本质其实就是把事件&#xff08;Touch&#xff09;封装成 MotionEvent 类&#xff0c;然后传递给 View 的层级处理。 MotionEvent 事件类型主要有…

51单片机-第七节-DS1302实时时钟

一、DS1302介绍&#xff1a; 实时时钟芯片&#xff0c;可对年&#xff0c;月&#xff0c;日&#xff0c;周&#xff0c;时&#xff0c;分&#xff0c;秒计时&#xff0c;是一种集成电路。 二、DS1302原理&#xff1a; 1.寄存器定义&#xff1a; Command&#xff1a;操作模式…