《疯狂java讲义》读书笔记(七):多线程

2023-11-04

《疯狂java讲义》读书笔记(七):多线程

1.线程和进程

​ 这两个概念必须得区分,之前学操作系统的时候我老给弄混了。
​ 进程的三种基本状态:

(1)运行态(running)
​ ​ ​ ​ ​ ​ ​ 当进程得到处理机,其执行程序正在处理机上运行时的状态称为运行状态。
​ ​ ​ ​ ​ ​ ​ 在单CPU系统中,任何时刻最多只有一个进程处于运行状态。在多CPU系统中,处于运行状态的进程数最多为处理机的数目。
(2)就绪状态(ready)
​​ ​ ​ ​ ​ ​ ​ 当一个进程已经准备就绪,一旦得到CPU,就可立即运行,这时进程所处的状态称为就绪状态。系统中有一个就绪进程队列,处于就绪状态进程按某种调度策略存在于该队列中。
(3)等待态(阻塞态)(Wait / Blocked )
​ ​ ​ ​ ​ ​ ​ 若一个进程正等待着某一事件发生(如等待输入输出操作的完成)而暂时停止执行的状态称为等待状态。 处于等待状态的进程不具备运行的条件,即使给它CPU,也无法执行。系统中有几个等待进程队列(按等待的事件组成相应的等待队列)。

​ 进程和线程的区别:
在这里插入图片描述
​​ ​ ​ ​ ​ ​ ​ 使用多线程编程的好处:进程之间不能共享内存,但是线程贡献内存就很方便系统创建进程时需要为该进程重新分配系统资源,但创建线程则代价小很多Java语言内置了多线程功能支持,而不是单纯的作为底层操作系统的调度方式,从而简化了Java多线程编程

2.线程的创建和启动

​​ ​ ​ ​ ​ ​ ​ 这部分内容说实话还挺熟悉的,还记得当时考Java,在b站看多线程的视频,当时期末考试还重点考了多线程hhhh。三种方式不多说。

2.1继承Thread类创建线程类

​ 直接写代码了。

//1.定义Thread子类
public class FirstThread extends Thread {
	private int i;
	//2.重写run方法,该run方法代表了线程需要完成的任务
	@Override
	public void run() {
		for (;i<100;i++){
			/**
			 * Thread对象的getName()返回当前线程的名字
			 * 当前线程类继承Thread,直接使用this就能获取当前线程
			 */
			System.out.println(getName()+" "+i);
		}
	}

	public static void main(String[] args) {
		for (int i=0;i<100;i++){
			System.out.println(Thread.currentThread().getName()+""+i);
			if (i==20){
				//3.创建Thread子类的实例,调用start方法启动线程
				new FirstThread().start();
				new FirstThread().start();
			}
			
		}
	}
}
2.2实现Runnable接口

​ 还是直接写代码了,用一个售票员卖票的例子说明。

public class Seller implements Runnable{
    private int ticket;
    public Seller(int ticket){
        this.ticket=ticket;
    }
    @Override
    public void run(){
        while (ticket>0){
            ticket--;
            System.out.println("剩余"+ticket+"张票");
        }
    }
}

主类。

public class Main {
    public static void main(String[] args) {
        System.out.println("开始卖票!");
        new Thread(new Seller(100)).start();
        new Thread(new Seller(20)).start();
    }
}
2.3使用Callable和Future
public class ThreadTest {

    public static void main(String[] args) {

        Callable<Integer> myCallable = new MyCallable();    // 创建MyCallable对象
        FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); //使用FutureTask来包装MyCallable对象

        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 30) {
                Thread thread = new Thread(ft);   //FutureTask对象作为Thread对象的target创建新的线程
                thread.start();                      //线程进入到就绪状态
            }
        }

        System.out.println("主线程for循环执行完毕..");
        
        try {
            int sum = ft.get();            //取得新创建的新线程中的call()方法返回的结果
            System.out.println("sum = " + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }
}


class MyCallable implements Callable<Integer> {
    private int i = 0;

    // 与run()方法不同的是,call()方法具有返回值
    @Override
    public Integer call() {
        int sum = 0;
        for (; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            sum += i;
        }
        return sum;
    }

}

3.线程的生命周期

​ ​ ​ ​ ​ ​ ​ 新建、就绪、运行、阻塞、死亡。

​ ​ ​ ​ ​ ​ ​ new关键字创建了一个线程之后,线程处于新建状态,此使它和其它对象一样,仅仅由JVM为其分为内存,并初始化其成员变量的值,此时的线程对象没有表现成任何线程的动态特征,程序也不会执行线程的线程执行体。当调用start()方法之后,线程处于就绪状态,JVM会为其创建方法调用栈和程序计数器,处于这个状态中的线程并没有开始运行,只是表示该线程可以运行了,至于啥时候开始,还是要取决于JVM里线程调度器的调度。

​ ​ ​ ​ ​ ​ ​ 如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态,如果计算机只有一个CPU,那么在任何时刻只有一个线程处于运行状态。当一个线程开始运行后,不可能总运行,线程在运行过程会被终端,目的是使其他线程获得执行的机会。当发生下列情况的时候,线程会进入阻塞状态。

  • 调用sleep()方法主动放弃所占用的处理器资源。

  • 线程调用了一个阻塞式IO方法,在该方法返回之前,该线程被阻塞。

  • 线程试图获得一个同步监视器,但该同步监视器整备其他线程所持有。

  • 线程在等待某个通知(notify)。

  • 程序调用了线程的suspend()方法将线程挂起,该方法容易造成死锁

    被阻塞的线程会在合适的时候重新进入就绪状态,注意是就绪状态不是运行态。

​ ​ ​ ​ ​ ​ ​ 线程会以三种方式结束,结束后处于死亡态。run()或者call()方法执行完成,线程正常结束。线程抛出一个没有捕获的Exception或者Error。直接调用该线程的stop()方法结束

​ ​ ​ ​ ​ ​ ​ 别对死亡状态的线程调用start()方法,程序只能对新建状态的线程使用start()方法,对一个新建状态的线程两次调用start()方法也是错误的。

4.控制线程

4.1 join线程

​​ ​ ​ ​ ​ ​ ​ 让一个线程等待另一个线程完成的方法。当在某个程序执行流中调用其它线程的join方法时,调用线程将被阻塞,一直到被join()方法加入的join线程执行完为止。

4.2 后台线程

​ ​ ​ ​ ​ ​ ​ JVM的垃圾回收线程就是典型的后台线程。后台线程有个特点就是如果所有前台线程都死亡,后台线程就会自动死亡。调用Thread对象的setDaemon(true)方法可指定线程设置为后台线程。

4.3线程睡眠:sleep

​ ​ ​ ​ ​ ​ ​ 让正在执行的线程暂停一会,进入阻塞状态。

4.4线程让步:yield

​ ​ ​ ​ ​ ​ ​ 和sleep()差不多,不过它是让正在执行的线程暂停,但它不会阻塞该线程,只是将该线程转入就绪状态。意思就是说,该方法只是让当前线程暂停下,让系统的线程调度器重新调度一次。

sleep()和yield()的区别

  • sleep()方法暂停当前线程后,会给其他线程执行机会,不会理会其他线程的优先级,但yield()只会给优先级相同或者更高的线程执行机会。
  • sleep()比yield()有更好的可移植性
  • sleep()会将线程转入阻塞态,直到经过阻塞时间才会转入就绪状态,而yield()不会将线程转入阻塞态
  • sleep()方法声明抛出了InterruptedException异常,所以调用sleep()方法时要么捕捉该异常,要么显式声明抛出该异常,而yield()没有声明抛出任何异常。

5.线程同步

5.1同步代码块

​​ ​ ​ ​ ​ ​ ​ 使用synchronized将某方法里的方法体修改成同步代码块。保证并发线程在任一时刻只有一个线程可以进入修改共享资源的代码区,所以同一时刻最多只有一个线程处于临界区内,从而保证线程安全。

5.2同步方法

​​ ​ ​ ​ ​ ​ ​ 就是用synchronized关键字就是某个方法。该类的对象可以被多个线程安全访问,每个线程调用该对象的任意方法之后都将得到正确结果,每个线程调用该对象的任意方法之后,该对象依然保持合理状态。

public synchronized void draw(double drawAmount){
  ...
}

synchronized可以修饰方法和代码块,但是构造器和成员变量不行。

6.线程通信

​ ​ ​ ​ ​ ​ ​ 传统的线程通信依赖于Object类中的wait()、notify()、notifyAll()三个方法,这三个方法不属于Thread类!!使用synchronized修饰的同步方法可以在方法内直接调用下列三个方法,因为默认实例就是同步监视器,但是如果是同步代码块,同步监视器就是synchronized后括号里的对象,必须使用该对象调用三个方法。

​​ ​ ​ ​ ​ ​ ​ wait():导致当前线程等待,直到其它线程调用该同步监视器的notify()或者notifyAll()方法来唤醒该线程。调用该方法的当前线程会释放对该同步监视器的锁定

​ ​ ​ ​ ​ ​ ​ notify():唤醒在此同步监视器上等待的单个线程。

​ ​ ​ ​ ​ ​ ​ notifyAll():唤醒再此同步监视器上等待的所有线程。

​ ​ ​ ​ ​ ​ ​ 当使用Lock对象保证同步的话,就不能用上面三个方法了,可以用Condition类来保持协调。对应的方法是await()、signal()、signalAll()

7.线程相关类

7.1 ThreadLocal类

​ ​ ​ ​ ​ ​ ​ 该类只提供了三个public方法。ThreadLocal将需要并发访问的资源复制多份,每个线程拥有一份资源,每个线程都拥有自己的资源副本,从而没有必要对该变量进行同步了。该类不同替代同步机制,面向的问题领域不同。ThreadLocal是为了隔离多个线程的数据贡献,从根本上避免多个线程之间对共享资源的竞争,而同步机制是为了同步多个线程对相同资源的并发访问,是多个线程之间进行通信的有效方式。

T get():返回此线程局部遍历中当前线程副本中的值。
void remove():删除此线程局部变量中当前线程的值。
void set(T value):设置此线程局部变量中当前线程副本的值。
7.2包装线程不安全的集合

​ ​ ​ ​ ​ ​ ​ 之前的读书笔记中提到过一些线程不安全的类,在那一节笔记中,也提到了Collections对这些类进行包装,使之成为线程安全的类。

7.3线程安全的集合类

​ ​ ​ ​ ​ ​ ​ 还记得有个包叫做java.util.concurrent嘛,它就提供了大量支持高并发访问的集合接口和实现类。不过这些集合类主要分为以Concurrent开头的集合类还有CopyOnWrite开头的集合类,在这里不多阐述了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

《疯狂java讲义》读书笔记(七):多线程 的相关文章

  • 重学java笔记「一」

    1 关于程序入口 所有的Java 程序由public static void main String args 方法开始执行 2 java支持的变量类型 2 1类变量 静态变量 独立于方法之外的变量 用 static 修饰 无论一个类创建了
  • org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document fro

    org springframework beans factory BeanDefinitionStoreException IOException parsing XML document from class path resource
  • 《14天从0到1学Java》第一天之07Java变量和常量

    这个是一套系列教程 一共14天 每天8篇 每篇需要5分钟 也就是说 你需要每天抽出40分钟来看教程 坚持14天就可以 轻松玩转JavaSE 我是Feri 我为自己代言 专注IT职场研发和教育N年 希望对于你的入门 有所帮助 本篇目录 一 常
  • 字符数组、字符串数组转换成字符串【JAVA基础】

    一 字符数组to字符串 直接声明 char c a b c String s new String c 二 字符串数组to字符串 string是不可变类 利用StringBuffer String str abc dfe hij Strin
  • springBoot框架简介入门教程(快速学习版)

    文章目录 回顾spring 优点 缺点 SpringBoot概述 SpringBoot特点 SpringBoot 的核心功能 SpringBoot自动配置 SpringBoot开发环境构建 SpringBoot配置文件 SpringBoot
  • Java Collection接口的子接口之Set接口及其Set接口的主要实现类HashSet,LinkedHashSet,TreeSet详解

    博主前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住也分享一下给大家 点击跳转到网站 一 Set接口的框架 1 Collection接口 单列集合 用来存储一个一个的对象 2 Set接口 存储无序的 不可重复的数据 说白了
  • spring中的RESTFUL风格是什么?

    什么是RestFul风格 RestFul是一种软件架构风格 设计风格 而不是标准 只是提供了一组设计原则和约束条件 它主要用于客户端和服务器交互类的一种代码编写风格 基于这个风格设计的软件可以更简洁 更有层次 更易于实现缓存等机制 来源 R
  • Java 中正则表达式的详解

    博主前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住也分享一下给大家 点击跳转到网站 前言 Java提供正则表达式技术 专门用于处理文本问题 简单的说 正则表达式 regular expression 是对字符串执行模式匹
  • Integer.parseInt(s)与Integer.valueOf(s)的区别详解

    一 Integer parseInt s 用法 String s1 1000 String s2 1000 int n1 Integer parseInt s1 int n2 Integer parseInt s2 if n1 n2 Sys
  • 基于IDEA的Java学生管理系统

    1 创建学生类 package studentManager public class Student 定义成员变量 private String num 学号 private String name 姓名 private String a
  • Java 运算符中 前++ 和后++ 的区别详解

    博主前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住也分享一下给大家 点击跳转到网站 一 前 和 后 的区别 具体在代码中给出 Test public void test3 前 先自加1 再运算 int a 10 int
  • Java学习笔记 -- 包 (package)

    Java 面向对象篇 笔记首页 序号 内容 链接地址 1 面向对象概述 https blog csdn net weixin 44141495 article details 107999131 2 类与对象 https blog csdn
  • day9:JAVA中while的用法

    一 while循环 while循环是先判断条件是否为真 如果条件为真 则执行循环体 语句形式 while 循环条件 一条语句 多条语句 循环体 二 do while循环 do while循环是先执行循环体 再根据条件确定是否能在执行循环体
  • SpringBoot总结

    一 SpringBoot简介 1 入门案例 SpringMVC的HelloWord程序大家还记得吗 SpringBoot是由Pivotal团队提供的全新框架 其设计目的是用来简化Spring应用的初始搭建以及开发过程 原生开发SpringM
  • Java——集合

    文章目录 1 集合概述 2 集合类体系结构 Collection集合体系 3 Collection集合常用API 3 Collection集合的遍历方式 方式一 迭代器 方式二 foreach 增强for循环 方式三 lambda表达式 4
  • Java静态修饰符static

    1 Satic注意事项 1 Static修饰的方法可以被类调用或者直接使用 而未被static修饰的方法是实例方法 属于对象的 必须用对象调用 2 类在方法区 方法在栈内存 对象在堆内存 3 静态只能访问静态 不能访问实例 实例可以访问静态
  • 使用IDEA实现java生成随机验证码

    package test200 checkCode 需求 定义方法实现随机产生一个5位的验证码 每位可能是数字 大写字母 小写字母 分析 定义一个方法 生成验证码返回 方法参数是位数 方法的返回值类型是String 在方法内部使用for循环
  • 调试代码

    1 用浏览器打开需要调试的页面 2 打开调试模式 在谷歌浏览器中 点击F12 可以打开开发者模式 刷新页面就可以看到数据的传输 也可以通过鼠标右键 选择 重新加载框架 可以查到某个部分的刷新 找到调用的接口 通过该接口去原程序中找到对应的方
  • Java 中do...while()的使用

    博主前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住也分享一下给大家 点击跳转到网站 do while语句 基本格式 do 循环体语句 while 条件判断语句 完整格式 初始化语句 do 循环体语句 条件控制语句 whi
  • Nginx 反向代理配置

    一 准备工作 Linux系统安装Tomcat 使用默认端口8080 启动Tomcat服务器 可以正常访问 接下来想要通过Nginx反向代理 转发请求到Tomcat服务器 对外暴露的是Nginx反向代理服务器的端口号 而Tomcat不对外暴露

随机推荐

  • Github Copilot 的补强工具Github Copilot Labs的常用功能介绍

    一 什么是Github Copilot Labs Github Copilot Labs是由GitHub推出的一款基于人工智能技术的代码协作工具 旨在协助开发者更加快速 高效地编写代码 该工具使用了机器学习技术 通过学习大量的开源代码和编写
  • Linux下Hadoop的介绍

    hadoop官网 http hadoop apache org 一 初始Hadoop 1 Hadoop是什么 Hadoop是Apache开源组织的一个分布式计算框架 可以在大量廉价硬件设备组成的集群上运行应用程序 并为应用程序提供一组稳定可
  • 最大间隙问题

    问题描述 最大间隙问题 给定n个实数 求这n个数在实轴上相邻2个数之间的最大差值 设计解最大间隙问题的线性时间算法 算法分析 问题很简单 而且描述本身就暗示了一种自然的求解方法 即先对元素排序 然后逐个求相邻元素的间距 这种解法的复杂度为O
  • Linux CentOS 修改MySQL安装目录

    安装MySQL 使用yum和Mysql官方源下载 安装方法参见 点此查看 Mysql 5 7源 修改Yum源 参照这里 修改安装目录 说明 仅针对还没有数据库数据的情况 有数据的请谨慎操作 虽然其实步骤似乎差不多 安装后的MySQL默认路径
  • linux开启rdp服务,让windows电脑mstsc远程,linux rdesktop远程windows机器

    windows 远程 linux桌面系统 windows7 CentOS release 6 9 1 安装 yum install xrdp 2 启动服务 service xrdp start 3 服务加入开机启动项 chkconfig x
  • MRTK-Unity学习记录

    TextMeshPro生成中文字体 Window TextMeshPro Font Asset Creator 1 Source Font File C盘 Windows Fonts 选择需要的字体文件 2 Atlas Resolution
  • Linux下安装Nginx

    一 什么是Nginx Nginx engine x 是一个高性能的 HTTP和反向代理服务器 也是一个 IMAP POP3 SMTP 服务器 正向代理 反向代理 很多大网站都是使用nginx做反向代理 应用非常广泛 Nginx是一款高性能的
  • Spring Boot 中的静态资源是什么,如何使用

    Spring Boot 中的静态资源是什么 如何使用 在 Web 应用程序中 静态资源通常是指不会动态生成的文件 例如图片 CSS JavaScript 文件等 Spring Boot 提供了一种简单的方式来处理这些静态资源 让我们可以更加
  • SpringMVC手写-核心逻辑

    文章目录 注解解析过程DispatcherServlet web xml Controller 自定义注解 从网上看到了SpringMVC实现的最简单版本 大致体现了核心逻辑 1 实现HttpServlet实现web请求访问 2 在实际处理
  • 批量获取力扣做题量工具

    这是一个批量统计国内版LeetCode做题量的工具 写这个小工具的起因是我们实验室准备每周统计大家leetcode的做题量 我们实验室十几个人 如果一人一个人看 太费时间了 作为高效程序员这不是我们做事的风格 于此就有了这个小工具 对于平常
  • matlab 基于密度的聚类算法,基于密度DBSCAN的聚类算法

    聚类算法概念 聚类分析又称群分析 它是研究 样品或指标 分类问题的一种统计分析方法 同时也是数据挖掘的一个重要算法 聚类 Cluster 分析是由若干模式 Pattern 组成的 通常 模式是一个度量 Measurement 的向量 或者是
  • mysqldump使用方法(MySQL数据库的备份与恢复)

    mysqldump使用方法 MySQL数据库的备份与恢复 mysqldump help 1 mysqldump的几种常用方法 1 导出整个数据库 包括数据库中的数据 mysqldump u username p dbname gt dbna
  • TCP三次握手

    三次握手指的是TCP协议建立连接的过程 当客户端请求与服务器建立TCP连接时 必须要经过三次握手才能真正建立连接 三次握手详细过程 第一次握手 客户端向服务器发送 SYN 报文 请求建立连接 其中 SYN 标志位被置为 1 同时客户端随机选
  • eclipse在java环境基础上配置C++环境(MinGW安装包+详细步骤)

    前言 在eclipse开发java的基础上 又不想再下一个c 的编辑器 如何实现java与c 的转换 博主整了两天 踩了好多坑 整理出来帮助大家 第一步 在eclipse里下载CDT 打开以后需要一点时间 搜索CDT 等待下载完成 补充说明
  • mac在pytorch环境下装transformer并成功实例运行

    主要是想成功运行下面这个安装步骤 https huggingface co transformers installation html installing from source 一 进入环境 conda activate pytorc
  • RuntimeError: cublas runtime error : unknown error at C:/w/b/win…cu:225

    报错 分析原因 GPU不够用 把数组改小就可以正常运行 或者改为在CPU上运行
  • Think in Java 复用类(第7章) 读书笔记

    第7章 复用类 1 组合语法 在新类中产生现有类的对象 由于新类是由现有类的对象组成的 所以这种方法称为组合 2 继承语法 按照现有类的类型来创建新类 无需改变现有类的形式 采用现有类的形式并在其中添加新代码 除非已经明确从其他类中继承 否
  • 程序的编译、链接与装载

    程序员的自我修养 链接装载与库 是一本值得推荐的书 主要介绍系统软件的运行机制和原理 涉及在Windows和Linux两个系统平台上 一个应用程序在编译 链接和运行时刻所发生的各种事项 包括 代码指令是如何保存的 库文件如何与应用程序代码静
  • 考研复试数据库原理课后习题(十三)——大数据管理

    大数据管理 1 什么是大数据 大数据有何特征 大数据是指无法在可容忍的时间内用现有IT技术和软硬件工具对其进行感知 获取 管理 处理和服务的数据集合 大数据的基本特征如下 大数据的首要特征是数据量巨大 而且在持续 急剧地膨胀 大数据异构的数
  • 《疯狂java讲义》读书笔记(七):多线程

    疯狂java讲义 读书笔记 七 多线程 1 线程和进程 这两个概念必须得区分 之前学操作系统的时候我老给弄混了 进程的三种基本状态 1 运行态 running 当进程得到处理机 其执行程序正在处理机上运行时的状态称为运行状态 在单CPU系统