Java-进阶:多线程2

目录

一、Lock 接口

二、线程间的通信

三、线程池

四、定时器 Timer

五、多线程和异常

一、Lock 接口

1. 线程锁

  • 是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问。一次只能有一个线程获得锁,对共享资源的所有访问都需要首先获得锁
//锁的使用
Lock l = new ReentrantLock(); //创建一个锁对象
l.lock();
try {// access the resource protected by this lock
} finally {l.unlock();
}
  • LockSynchronize更为灵活的功能:
  • boolean tryLock()仅在调用时锁为空闲状态才获取该锁。如果锁可用,则获取锁,并立即返回值 true。如果锁不可用,则此方法将立即返回值 false。

2. 同步弊端

  • 影响效率
  • 如果出现了嵌套锁,容易产生死锁

3. 死锁

  • 死锁:死锁是指两个以上的线程在执行过程中,因为争夺资源而产生的一种相互等待的现象

二、线程间的通信

1. wait()

  • 导致当前线程处于等待状态
  • 只有在其他线程线程中调用了notify()方法或 notifyAll()来唤醒,因为 wait()方法阻塞了线程
  • 在调用 wait方法之前,当前线程必须拥有此对象监视器(锁对象),换句话说,必须在 锁对象 上调用 wait方法(此方法只应该由作为此对象监视器的所有者的线程 来调用)
  • 一旦在锁对象上调用了 wait方法,紧接着:
    • 当前线程放弃 cpu 执行权,并等待
    • 放弃持有的 锁对象

wait()sleep()比较
相同点:使当前线程放弃cpu执行权,处于阻塞状态
不同点

  1. 线程因为 sleep() 方法 处于阻塞状态的时候,不会放弃所持有的锁对象;线程因为wait() 处于阻塞状态的时候,会放弃锁对象
  2. 使用条件sleep() 没有任何特殊条件; 使用 wait() 则必须持有锁,在锁对象上调用**wait()**方法
  3. 唤醒条件sleep() 的唤醒条件是休眠时间结束;wait() 被唤醒,只能是在其它线程中调用了同一个锁对象的 notify() 或者 **notifyAll()**方法

2. nofity()

  • 唤醒在此对象(调用wait的同一个锁对象) 监视器上等待的单个线程;如果所有线程都在此对象上等待,则会选择唤醒其中一个线程
  • 直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程
  • 被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争

3. notifyAll()

  • 唤醒在此对象监视器上等待的所有线程

三、线程池

1. 概述

  • 我们创建一个线程,只能使用一次
  • 线程池,其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源
  • 线程池的原理:线程池里每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一次被使用

为什么要使用线程池?

  1. 在 java 中,如果每个请求到达就创建一个新线程,开销是相当大的。在实际使用中,创建和销毁线程花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多。
  2. 除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。如果在一个jvm里创建太多的线程,可能会使系统由于过度消耗内存或“切换过度”而导致系统资源不足。
  3. 为了防止资源不足,需要采取一些办法来限制任何给定时刻处理的请求数目,尽可能减少创建和销毁线程的次数,特别是一些资源耗费比较大的线程的创建和销毁,尽量利用已有对象来进行服务。
  4. 线程池主要用来解决线程生命周期开销问题和资源不足问题。通过对多个任务重复使用线程,线程创建的开销就被分摊到了多个任务上了,而且由于在请求到达时线程已经存在,所以消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使用应用程序响应更快。另外,通过适当的调整线程中的线程数目可以防止出现资源不足的情况。

2. 创建线程池

  • 通常,线程池都是通过 线程池工厂 创建,再调用线程池中的方法获取线程,再通过线程去执行任务方法Executors:线程池创建工厂类
  • public static ExecutorService newCachedThreadPool()
    • 创建一个可根据需要创建新线程 的线程池,但是在以前构造的线程可用时将重用它们 (可变)
    • 对于执行很多短期异步(短但是频繁) 任务的程序而言,这些线程池通常可提高程序性能
    • 如果现有线程没有可用的,则创建一个新线程并添加到池中
    • 终止并从缓存中移除那些已有 60 秒钟未被使用的线程(折中)
  • public static ExecutorService newFixedThreadPool(int nThreads)
    • 创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程
    • 如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待
  • public static ExecutorService newSingleThreadExecutor()
    • 创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程
    • 可保证顺序地执行各个任务
  • 以上方法返回了一个ExecutorService,该对象表示一个线程池,它可以执行 Runable对象代表的线程。

3. 提交任务

  • Runnable 接口
  • Callable 接口类似于 Runnable,用来指定线程的任务。其中的 call() 方法,用来返回线程任务执行完毕后的结果,call方法可抛出异常
  • ExecutorService:线程池类
  • <T> Future<T> **submit**(Callable<T> task):获取线程池中的某一个线程对象,并执行线程中的call()方法
  • Future接口:用来记录线程任务执行完毕后产生的结果
    • get()获取 Future对象中封装的数据结果
  • void shutdown():启动一次顺序关闭,执行以前提交的任务,但 不接受新任务
  • shutdownNow()方法: 试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。

4. 使用线程池中线程对象的步骤:

  • 创建线程池对象
  • 创建 Runnable 接口/Callable接口 子类对象
  • 提交 Runnable 接口/Callable接口 子类对象
  • 关闭线程池
public class ThreadPool {public static void main(String[] args) throws ExecutionException, InterruptedException {//创建一个newCachedThreadPoolExecutorService executorService = Executors.newFixedThreadPool(5);//操作线程池//向线程池提交任务executorService.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello, thread pool");}});//Callable接口的使用Future<Integer> future = executorService.submit(new Callable<Integer>() {@Overridepublic Integer call() throws Exception {TimeUnit.SECONDS.sleep(3);int sum = 0;for (int i = 0; i < 10; i++) {sum += i;}return sum;}});System.out.println(future);System.out.println(future.get());}
}

四、定时器 Timer

1. 概述

  • 调度定时任务,帮助我们在稍后的时刻执行定时任务。一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务 执行一次,或者 定期重复执行

2. TimerTask 定时任务

  • 定时任务TimerTask对象表示定时任务
  • Timer调度定时任务,定时任务的内容由TimerTaskrun方法 运行决定
  • 在 timer 中所有的定时任务都是运行在同一个线程中
  1. cancel 取消定时任务
  • 如果利用TimerTaskcancel要取消定时任务,在定时任务已经开始运行时, 调用cancel方法,是没有效果
    利用Timercancel方法取消定时任务,其实是终止Timer本身
public class TimerDemo {public static void main(String[] args) {//定义一个定时器// 在timer中所有的定时任务都是运行在同一个线程中Timer timer = new Timer(); //默认不是守护线程//在定时器上调度,定时任务timer.schedule(new MyTimerTask(), 3000);timer.schedule(new MyTimerTask(), 1000);//调度器重复执行定时任务timer.schedule(new MyTimerTask(timer), 0, 2000);}
}class MyTimerTask extends TimerTask {Timer timer;public MyTimerTask(Timer timer) {this.timer = timer;}@Overridepublic void run() {//在输出之前,取消定时任务//cancel();//利用Timer的cancel方法取消定时任务,其实timer的cance方法,是终止Timer本身timer.cancel();System.out.println("hello timer");}
}

五、多线程和异常

  • 在 Thread 类中,不可以抛出编译型异常,但是可以抛出运行时异常
  • 当 运行时异常抛出线程(溢出线程),能不能捕获?

java语言,并不能直接用try-catch代码块捕获,溢出线程的异常,这是java语言实现上的一个遗憾,但是,并不是说,溢出线程的异常开发者就没办法捕获了。—> Thread.UncaughtExceptionHandler

  • static setDefaultUncaughtExceptionHandler,处理所有线程中未捕获的异常(溢出线程的异常)
  • setUncaughtExceptionHandler,处理某一个线程中的未捕获的异常(溢出线程的异常)
public class supplement01 {public static void main(String[] args) {//我们可以通过设置UncaughtExceptionHandler对象,让该对象捕获溢出线程的异常// callback 回调Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {@Overridepublic void uncaughtException(Thread t, Throwable e) {// 这个方法,会在日志模块 -》 将这些异常信息,通过流保存到文件中//处理溢出线程的异常System.out.println("DefaultUncaughtExceptionHandler");}});//在主线程中捕获异常CatchThreadException1 catchThreadException = new CatchThreadException1();catchThreadException.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {@Overridepublic void uncaughtException(Thread t, Throwable e) {System.out.println("Thread t" + e.getMessage());}});try{//试图在主线程捕获子线程抛出的异常catchThreadException.start();}catch (Exception e) {System.out.println("我捕获到了异常");}}
}class CatchThreadException extends Thread {@Overridepublic void run() {//将异常抛出run方法之外,就等价于将该抛出了线程throw new RuntimeException("测试抛出线程的异常");}
}class CatchThreadException1 extends Thread {@Overridepublic void run() {//将异常抛出run方法之外,就等价于将该抛出了线程throw new RuntimeException("测试抛出线程的异常");}
}
ew RuntimeException("测试抛出线程的异常");}
}class CatchThreadException1 extends Thread {@Overridepublic void run() {//将异常抛出run方法之外,就等价于将该抛出了线程throw new RuntimeException("测试抛出线程的异常");}
}

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

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

相关文章

Java周总结1

一、计算机高级编程语言类型&#xff1a; a.编译型 b.解释型 Hello.java Java源文件 编译 Hello.class 字节码文件 解释 01101100.... &#xff08;二进制&#xff09;机器码指令 computer…

MMKV集成与原理,先收藏了

标准文档流 标准文档流&#xff0c;指的是元素排版布局过程中&#xff0c;元素会默认自动从左往右&#xff0c;从上往下的流式排列方式。前面内容发生了变化&#xff0c;后面的内容位置也会随着发生变化。 HTML就是一种标准文档流文件 HTML中的标准文档流特点通过两种方式体现…

Java周总结3

撰写第三周课程总结及实验报告&#xff08;一&#xff09; Java实验报告 班级 计科一班 学号 20188375 姓名 汤云云 完成时间 评分等级 实验一 Java开发环境与简单Java程序 一、 实验目的 &#xff08;1&#xff09; 熟悉JDK开…

MMKV集成与原理,吊打面试官系列!

前言 校招 -1 年 这个阶段还属于成长期&#xff0c;更需要看重的是你的基础和热情。对于 JS 基础&#xff0c;计算机基础&#xff0c;网络通信&#xff0c;算法等部分的要求会相对高一些。毕竟这个阶段比较难考察你的业务项目中的沉淀&#xff0c;所以只能从基础部分入手考察。…

CV2摄像头人脸、人眼、微笑等检测

import cv2face_cascade cv2.CascadeClassifier(cv2.data.haarcascades haarcascade_frontalface_default.xml)#人脸 eye_cascade cv2.CascadeClassifier(cv2.data.haarcascades haarcascade_eye.xml)#人眼 smile_cascadecv2.CascadeClassifier(cv2.data.haarcascades haa…

MMKV集成与原理,成功跳槽阿里!

前言 在初学前端的时候&#xff0c;我们总会遇到一些问题&#xff0c;我们可以在网上看到很多关于前端的这些问题&#xff1a; 你们都是怎么学web前端的&#xff1f; 零基础&#xff0c;怎么自学好前端&#xff1f; 前端需要学多久&#xff0c;都学哪些知识&#xff1f; 想成为…

第四周课程总结试验报告(二)

Java实验报告 实验二 Java简单类与对象 一、 实验目的 &#xff08;1&#xff09; 掌握类的定义&#xff0c;熟悉属性、构造函数、方法的作用&#xff0c;掌握用类作为类型声明变量和方法返回值&#xff1b; &#xff08;2&#xff09; 理解类和对象的区别&#xff0c;掌握构造…

MMKV集成与原理,薪资翻倍

毕业工作一年之后&#xff0c;有了转行的想法&#xff0c;偶然接触到程序员这方面&#xff0c;产生了浓厚且强烈的兴趣&#xff0c;开始学习前端&#xff0c;成功收割了大厂offer&#xff0c;开始了我的程序员生涯。 在自学过程中有过一些小厂的面试经历&#xff0c;也在一些小…

Spring入门与常用配置

什么是Spring Spring&#xff1a;SE/EE开发的一站式框架。 一站式框架&#xff1a;有EE开发的每一层解决方案。 WEB层 &#xff1a;SpringMVC Service层 &#xff1a;Spring的Bean管理&#xff0c;Spring声明式事务 DAO层 &#xff1a;Spring的Jdbc模板&#xff0c;Spring的ORM…

MMKV集成与原理,详细学习指南

前言 本文主要是javascript和css方面的基础面试题&#xff0c;适合面试前以及平时复习食用。 基础知识是前端一面必问的&#xff0c;如果你在基础知识这一块翻车了&#xff0c;就算你框架玩的再6&#xff0c;webpack、git、node学习的再好也无济于事&#xff0c;因为对方就不…

第五周课程总结实验报告(三)

实验三 String类的应用 一、实验目的 &#xff08;1&#xff09; 掌握类String类的使用&#xff1b; &#xff08;2&#xff09; 学会使用JDK帮助文档&#xff1b; 二、实验内容 1.已知字符串&#xff1a;"this is a test of java".按要求执行以下操作&#xff1a;&a…

MMKV集成与原理,赶紧学起来

开头 Web前端开发基础知识学习路线分享&#xff0c;前端开发入门学习三大基础&#xff1a;HTML、CSS、JavaScript。除此之外还要学习数据可视化、Vue、React、Angular相关框架&#xff0c;熟练运用框架提升开发效率&#xff0c;提升稳定性。 [外链图片转存失败,源站可能有防盗…

MMKV集成与原理,轻松拿下offer

从事前端开发工作差不多3年了&#xff0c;自己也从一个什么都不懂的小白积累了一定的理论和实践经验&#xff0c;并且自己也对这3年来的学习实践历程有一个梳理&#xff0c;以供后面来细细回忆品味。 1、为什么选择学习前端开发&#xff1f; 你可能是因为兴趣&#xff0c;完成…

React面试题总结,一文说清!

前言 JavaScript是面向 Web 的编程语言&#xff0c;获得了所有网页浏览器的支持&#xff0c;是目前使用最广泛的脚本编程语言之一&#xff0c;也是网页设计和 Web 应用必须掌握的基本工具。 JavaScript主要用途 嵌入动态文本与HTML页面对浏览器时间做出相应读写HTML元素在数…

React面试题总结,含爱奇艺,小米,腾讯,阿里

前言 校招 -1 年 这个阶段还属于成长期&#xff0c;更需要看重的是你的基础和热情。对于 JS 基础&#xff0c;计算机基础&#xff0c;网络通信&#xff0c;算法等部分的要求会相对高一些。毕竟这个阶段比较难考察你的业务项目中的沉淀&#xff0c;所以只能从基础部分入手考察。…

React面试题总结,就是这么简单

前言 昨天有幸去字节面试了&#xff0c;顺便拿到了offer&#xff0c;把还记得的东西写下来&#xff0c;供大家参考一下。 计算机网络篇 HTTP HTTP 报文结构是怎样的&#xff1f;HTTP有哪些请求方法&#xff1f;GET 和 POST 有什么区别&#xff1f;如何理解 URI&#xff1f;如…

CSS清除默认样式,成功入职腾讯

前言 又逢金三银四&#xff0c;拿到大厂的offer一直是程序员朋友的一个目标&#xff0c;我是如何拿到大厂offer的呢&#xff0c;今天给大家分享我拿到大厂offer的利器&#xff0c;前端核心知识面试宝典&#xff0c;内容囊括Html、CSS、Javascript、Vue、HTTP、浏览器面试题\数…

CSS清除默认样式,技术详细介绍

前言 JavaScript是面向 Web 的编程语言&#xff0c;获得了所有网页浏览器的支持&#xff0c;是目前使用最广泛的脚本编程语言之一&#xff0c;也是网页设计和 Web 应用必须掌握的基本工具。 JavaScript主要用途 嵌入动态文本与HTML页面对浏览器时间做出相应读写HTML元素在数…

CSS清除默认样式,看完这篇彻底明白了

前端的兴起 前端真正兴起和开始频繁出现在大家的视线里&#xff0c;大概是在十年前。彼时的 Web 开发基本是由后端主导&#xff0c;前端能做的只是校验一下数据、操作一下 DOM。&#xff08;其中数据检验是 JS 产生的根本原因&#xff1a;当时网络太慢&#xff0c;在服务端检验…

合并两个链表,去掉重复元素

最近在学习机器学习的相关算法&#xff0c;写到DbScan算法发现在簇扩展时用到两个邻域中的点会重合&#xff0c;于是尝试了合并两个链表的两个算法。 最初用到这个方法&#xff0c;认为它简单易用。思路是定义一个链表存放合并后的链表list&#xff0c;首先往该链表中加入a链表…