高并发编程之多线程锁和CallableFuture 接口

news2024/11/25 4:58:46

5 多线程锁

5.1 锁的八个问题演示

package com.xingchen.sync;

import java.util.concurrent.TimeUnit;

class Phone {

    public static synchronized void sendSMS() throws Exception {
        //停留4秒
        TimeUnit.SECONDS.sleep(4);
        System.out.println("------sendSMS");
    }

    public synchronized void sendEmail() throws Exception {
        System.out.println("------sendEmail");
    }

    public void getHello() {
        System.out.println("------getHello");
    }
}

/**
 * @author xing'chen
 * @Description: 8锁
 *
1 标准访问,先打印短信还是邮件
------sendSMS
------sendEmail

2 停4秒在短信方法内,先打印短信还是邮件
------sendSMS
------sendEmail

3 新增普通的hello方法,是先打短信还是hello
------getHello
------sendSMS

4 现在有两部手机,先打印短信还是邮件
------sendEmail
------sendSMS

5 两个静态同步方法,1部手机,先打印短信还是邮件
------sendSMS
------sendEmail

6 两个静态同步方法,2部手机,先打印短信还是邮件
------sendSMS
------sendEmail

7 1个静态同步方法,1个普通同步方法,1部手机,先打印短信还是邮件
------sendEmail
------sendSMS

8 1个静态同步方法,1个普通同步方法,2部手机,先打印短信还是邮件
------sendEmail
------sendSMS

 */

public class Lock_8 {
    public static void main(String[] args) throws Exception {

        Phone phone = new Phone();
        Phone phone2 = new Phone();

        new Thread(() -> {
            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "AA").start();

        Thread.sleep(100);

        new Thread(() -> {
            try {
               // phone.sendEmail();
               // phone.getHello();
                phone2.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "BB").start();
    }
}

结论 :

一个对象里面如果有多个 synchronized 方法,某一个时刻内,只要一个线程去调用其中的

一个 synchronized 方法了,

其它的线程都只能等待,换句话说,某一个时刻内,只能有唯一一个线程去访问这些

synchronized 方法

锁的是当前对象 this,被锁定后,其它的线程都不能进入到当前对象的其它的

synchronized 方法

加个普通方法后发现和同步锁无关

换成两个对象后,不是同一把锁了,情况立刻变化。

synchronized 实现同步的基础:Java 中的每一个对象都可以作为锁。

具体表现为以下 3 种形式。

  • 对于普通同步方法,锁是当前实例对象。
  • 对于静态同步方法,锁是当前类的 Class 对象。
  • 对于同步方法块,锁是 Synchonized 括号里配置的对象

当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常时必须释放锁。

也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,可是别的实例对象的非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,所以毋须等待该实例对象已获取锁的非静态同步方法释放锁就可以获取他们自己的锁。所有的静态同步方法用的也是同一把锁——类对象本身,这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,只要它们同一个类的实例对象!

6 Callable&Future 接口

6.1 Callable 接口

目前我们学习了有两种创建线程的方法-一种是通过创建 Thread 类,另一种是

通过使用 Runnable 创建线程。但是,Runnable 缺少的一项功能是,当线程

终止时(即 run()完成时),我们无法使线程返回结果。为了支持此功能,

Java 中提供了 Callable 接口。

现在我们学习的是创建线程的第三种方案—Callable 接口

Callable 接口的特点如下(重点)

• 为了实现 Runnable,需要实现不返回任何内容的 run()方法,而对于

Callable,需要实现在完成时返回结果的 call()方法。

• call()方法可以引发异常,而 run()则不能。

• 为实现 Callable 而必须重写 call 方法

• 不能直接替换 runnable,因为 Thread 类的构造方法根本没有 Callable

    创建新类 MyThread 实现 runnable 接口
class MyThread implements Runnable{
    @Override
    public void run() {
    }
}
    新类 MyThread2 实现 callable 接口
class MyThread2 implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        return 200;
    }
}

6.2 Future 接口

当 call()方法完成时,结果必须存储在主线程已知的对象中,以便主线程可

以知道该线程返回的结果。为此,可以使用 Future 对象。将 Future 视为保存结果的对象–它可能暂时不保存结果,但将来会保存(一旦

Callable 返回)。Future 基本上是主线程可以跟踪进度以及其他线程的结果的

一种方式。要实现此接口,必须重写 5 种方法,这里列出了重要的方法,如下:

public boolean cancel(boolean mayInterrupt): 用于停止任务。

==如果尚未启动,它将停止任务。如果已启动,则仅在 mayInterrupt 为 true

时才会中断任务。==

public Object get()抛出 InterruptedException,ExecutionException:

用于获取任务的结果。

==如果任务完成,它将立即返回结果,否则将等待任务完成,然后返回结果。

==

public boolean isDone(): 如果任务完成,则返回 true,否则返回 false

可以看到 Callable 和 Future 做两件事-Callable 与 Runnable 类似,因为它封

装了要在另一个线程上运行的任务,而 Future 用于存储从另一个线程获得的结

果。实际上,future 也可以与 Runnable 一起使用。

要创建线程,需要 Runnable。为了获得结果,需要 future。

6.3 FutureTask

Java 库具有具体的 FutureTask 类型,该类型实现 Runnable 和 Future,并方

便地将两种功能组合在一起。 可以通过为其构造函数提供 Callable 来创建

FutureTask。然后,将 FutureTask 对象提供给 Thread 的构造函数以创建

Thread 对象。因此,间接地使用 Callable 创建线程。

核心原理:(重点)

在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些

作业交给 Future 对象在后台完成

• 当主线程将来需要时,就可以通过 Future 对象获得后台作业的计算结果或者执

行状态• 一般 FutureTask 多用于耗时的计算,主线程可以在完成自己的任务后,再去

获取结果。

• 仅在计算完成时才能检索结果;如果计算尚未完成,则阻塞 get 方法

• 一旦计算完成,就不能再重新开始或取消计算

• get 方法而获取结果只有在计算完成时获取,否则会一直阻塞直到任务转入完

成状态,然后会返回结果或者抛出异常

• get 只计算一次,因此 get 方法放到最后

demo 案例

6.4 使用 Callable 和 Future

CallableDemo 案例

/**
 * CallableDemo 案列
 */
public class CallableDemo {
    /**
     * 实现 runnable 接口
     */
    static class MyThread1 implements Runnable{
        /**
         * run 方法
         */
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName() + "线程进入了 run
                        方法");
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    /**
     * 实现 callable 接口
     */
    static class MyThread2 implements Callable{
        /**
         * call 方法
         * @return
         * @throws Exception
         */
        @Override
        public Long call() throws Exception {
            try {
                System.out.println(Thread.currentThread().getName() + "线程进入了 call
                        方法,开始准备睡觉");
                        Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + "睡醒了");
            }catch (Exception e){
                e.printStackTrace();
            }
            return System.currentTimeMillis();
        }
    }
    public static void main(String[] args) throws Exception{
        //声明 runable
        Runnable runable = new MyThread1();
        //声明 callable
        Callable callable = new MyThread2();
        //future-callable
        FutureTask<Long> futureTask2 = new FutureTask(callable);
        //线程二
        new Thread(futureTask2, "线程二").start();
        for (int i = 0; i < 10; i++) {
            Long result1 = futureTask2.get();
            System.out.println(result1);
        }
        //线程一
        new Thread(runable,"线程一").start();
    }
}

6.5 小结(重点)

• 在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些

作业交给 Future 对象在后台完成, 当主线程将来需要时,就可以通过 Future

对象获得后台作业的计算结果或者执行状态• 一般 FutureTask 多用于耗时的计算,主线程可以在完成自己的任务后,再去

获取结果

• 仅在计算完成时才能检索结果;如果计算尚未完成,则阻塞 get 方法。一旦计

算完成,就不能再重新开始或取消计算。get 方法而获取结果只有在计算完成

时获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或者抛出异

常。

• 只计算一次

文件的所有图片

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

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

相关文章

AXI协议规范超详细中文总结版

link AXI协议规范中文翻译版 来源&#xff1a;https://github.com/lizhirui/AXI_spec_chinese 综述 本文参考分析整理总结了AMBA AXI and ACE Protocol Specification文档的AXI总线协议规范部分&#xff0c;错误之处欢迎指出。 AMBA AXI协议支持高性能高频的系统设计&#xff0…

【视觉高级篇】25 # 如何用法线贴图模拟真实物体表面

说明 【跟月影学可视化】学习笔记。 什么是法线贴图&#xff1f; 法线贴图就是在原物体的凹凸表面的每个点上均作法线&#xff0c;通过RGB颜色通道来标记法线的方向&#xff0c;你可以把它理解成与原凹凸表面平行的另一个不同的表面&#xff0c;但实际上它又只是一个光滑的平…

巧用 Chrome:网络知多少

开发者如数家珍的工具中&#xff0c;Chrome 想必是众多人心目中的白月光&#xff0c;倒也不是它有多么优秀&#xff0c;而是多亏同行浏览器们的衬托。其开源的内核 Chromium 也成就众多养家糊口的岗位&#xff0c;比如 Edge、Opera、QQ 浏览器、360 浏览器等等国内外一票浏览器…

物联网开发笔记(62)- 使用Micropython开发ESP32开发板之控制ILI9341 3.2寸TFT-LCD触摸屏进行LVGL图形化编程:环境搭建

一、目的 这一节我们学习如何使用我们的ESP32开发板来控制ILI9341 3.2寸TFT-LCD触摸屏进行LVGL图形化编程的第一步&#xff1a;环境搭建。 关键字&#xff1a;3.2寸SPI串口TFT液晶显示屏模块 ILI9341驱动 LCD触摸屏 240*320 LVGL图形化编程 XPT2046触摸屏芯片IC 二、环境 ESP…

实机安装CentOS7.9操作系统图文(保姆级)教程

一、制作启动U盘 1、下载Ventoy软件 去Ventoy官网下载Ventoy软件&#xff08;Download . Ventoy&#xff09;如下图界面 ​ 2、制作启动盘 选择合适的版本以及平台下载好之后&#xff0c;进行解压&#xff0c;解压出来之后进入文件夹&#xff0c;如下图左边所示&#xff0c…

Hive 之数据透视表

文章目录什么是数据透视表&#xff1f;创建数据源基于各产品在各个平台半年内的月销售额与汇总&#xff0c;制作数据透视表什么是数据透视表&#xff1f; 数据透视表是一种工具&#xff0c;用于帮助用户理解和分析大量数据。它通常是一个二维表格&#xff0c;可以让用户以不同…

java计算机毕业设计springboot+vue航空公司电子售票系统-机票预订系统

项目介绍 通篇文章的撰写基础是实际的应用需要,然后在架构系统之前全面复习大学所修习的相关知识以及网络提供的技术应用教程,以远程教育系统的实际应用需要出发,架构系统来改善现远程教育系统工作流程繁琐等问题。不仅如此以操作者的角度来说,该系统的架构能够对多媒体课程进…

手把手教你使用SpringBoot做一个员工管理系统【代码篇·下】

手把手教你使用SpringBoot做一个员工管理系统【代码篇下】1.增加员工实现2.修改员工信息3.删除员工4.404页面配置5.注销1.增加员工实现 新增添加员工的按钮&#xff1a; <h2><a class"btn btn-sm btn-success" th:href"{/addemp}">添加员工&…

0- LVGL移植基于野火STM32F429挑战者(LVGL8.2)

1-移植准备 LVGL8.2 野火STM32F429_v2开发板 因为ST在STM32F4之后所有的芯片都不在有标准库,因此本篇是基于HAL库的。同时现在有许多厂商都不在有标准库了,都是根据自己的开发环境进行一些基本芯片接口的配置。像NXP,ST等。 这里不过多介绍LVGL,既然看到这个文章,大多数是…

20221214英语学习

今日新词&#xff1a; minus prep.减去&#xff1b;&#xff08;温度&#xff09;零下 garlic n.【植】大蒜 linger v.停留&#xff0c;逗留&#xff1b;徘徊&#xff1b;继续留存&#xff0c;缓慢消失&#xff1b;苟延残喘 sarcastic adj.讽刺的, 嘲讽的, 挖苦的 data n.…

【LeetCode每日一题】——572.另一棵树的子树

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【时间频度】九【代码实现】十【提交结果】一【题目类别】 树 二【题目难度】 简单 三【题目编号】 572.另一棵树的子树 四【题目描述】 给你两棵二叉树…

MySQL索引优化(二)

文章目录一、查询优化1. 索引失效&#xff08;1&#xff09;不满足最左前缀法则&#xff0c;索引失效&#xff08;2&#xff09;在索引列上做任何计算、函数操作&#xff0c;索引失效&#xff08;3&#xff09;存储引擎使用索引中范围条件右边的列&#xff0c;索引失效&#xf…

倪健中会长应邀出席首届世界数贸易博览会致辞:把杭州打造成全球数字贸易元宇宙之都

12月11日至14日&#xff0c;首届全球数字贸易博览会在浙江省杭州市盛大举办。博览会由浙江省人民政府和商务部联合主办&#xff0c;杭州市人民政府、浙江省商务厅和商务部贸发局共同承办&#xff0c;主题为“数字贸易商通全球”&#xff0c;爱尔兰为主宾国&#xff0c;北京、上…

大航海时代:葡萄牙、西班牙率先出发,英国为何成为最大赢家?

欧洲经历了长达千年的中世纪以后&#xff0c;忽然开始自我反省了。为啥&#xff1f;因为打了上千年&#xff0c;不仅社会没进步&#xff0c;反而因为各种瘟疫、战争&#xff0c;把人口搞掉了一大半。 这么玩下去&#xff0c;日耳曼人的各大分支&#xff0c;可能都要完犊子了&a…

基于java+springboot+mybatis+vue+mysql的智能热度分析和自媒体推送平台

项目介绍 前端页面&#xff1a; 功能&#xff1a;首页、文章信息、图片信息、视频信息、个人中心、后台管理 管理员后台管理页面&#xff1a; 功能&#xff1a;首页、个人中心、用户管理、文章类型管理、文章信息管理、图片类型管理、图片信息管理、视频类型管理、视频信息管…

数据工厂刷新PowerBI数据集2

前面已经介绍过数据工厂中刷新PowerBI数据集&#xff0c;我们先发起一个web请示获取了token&#xff0c;然后再把token传入到接口中从而刷新数据集。 但是&#xff0c;明明都是微软家的产品&#xff0c;竟然还需要先获取token?明明Power Apps、Power Automate里都不需要的啊&…

茶文化推广网站

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a; 网型站前台&#xff1a;网站个介绍、帮助信总、茶文化、茶叶分享、讨论信总 管理功能&#xff1a; 1、管理网站介绍、帮…

刚做外贸,先做平台好还是独立站好?

作为亚马逊这样的平台卖家&#xff0c;依托平台完善的第三方服务和流量红利&#xff0c;很容易将产品卖到海外。如今&#xff0c;随着平台要求越来越严格&#xff0c;管理政策越来越多变&#xff0c;用户需求也越来越多样化和苛刻&#xff0c;卖家在平台上经营店铺的一些问题正…

[附源码]Python计算机毕业设计SSM基于Web的摄影爱好者交流社区(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Clone使用

实现克隆接口:clone方法是默认是Object的方法 1)这个接口是一个标记性的接口(空接口)&#xff0c;他们内部都没有方法和属性&#xff0c;实现这个接口表示这个对象都可以进行克隆&#xff0c;我们调用Object对象的Object.clone()方法&#xff0c;如果没有实现Cloneable的类对象…