Java-多线程基本知识学习总结

多线程

    • 前言
    • 一、线程的创建
      • 1、继承Thread类
      • 2、实现Runnable接口
    • 二、线程的生命周期
    • 三、操作线程的方法
      • 1、线程的休眠
      • 2、线程的加入
      • 3、线程的礼让
      • 4、线程的优先级
    • 四、线程同步
    • End

前言

Java是支持多线程的编程语言,所谓多线程就是程序能够同时完成多种操作。
计算机完成可以多种操作同时进行,这种思想在Java中被称为并发,而将并发完成的多种操作被称为线程。



一、线程的创建

在Java中线程的创建一般分为两种方式:

  • 继承Thread类创建
  • 实现Runnable接口创建

1、继承Thread类

Java中的Thread类是java.lang包中的核心类,它代表一个线程。它主要用于创建新线程并在其中执行自定义任务。

Thread类的主要特点包括:

  1. 继承性:Thread类是java.lang.Object的子类,因此可以继承Object类的属性和方法。
  2. 抽象性:Thread类是一个抽象类,这意味着它不能直接实例化。为了使用Thread类,我们需要创建一个Thread的子类,并重写其run()方法。
  3. 线程安全性:Thread类是线程安全的,这意味着多个线程可以同时调用Thread类的方法,而不会导致数据不一致或其他并发问题。
  4. 常用方法:Thread类有许多有用的方法,包括start()(启动线程)、run()(执行线程)、sleep()(使线程休眠)、interrupt()(中断线程)等。

继承Thread类创建一个新的线程语法:

public class MyThread extends Thread {  @Override  public void run() {  // 在这里编写线程需要执行的代码  System.out.println("My thread is running.");  }  
}

完成线程真正功能的代码放置在run方法中执行,该线程在执行完run方法中的代码后就会停止。

示例:

public class demo_1 {public static void main(String[] args) {/*实现方式:1自定义一个类继承Thread、或者构建Thread对象,重写run方法重写run方法启动线程*/MyThread t1=new MyThread();MyThread t2=new MyThread();// 为线程指定名字t1.setName("线程一");  t2.setName("线程二");t1.start(); // 开启线程t2.start(); // 开启线程}
}
class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(getName()+ "芜湖");}}
}



2、实现Runnable接口

上一种方式创建线程的方式,是通过继承Thread类的方式创建的,但是Java是只支持单继承的语言,所以如果通过上一个方式创建线程的话,拓展性不太好。因此就可以使用实现接口的方式来创建线程。

实现过程:

  1. 自定义一个类实现Runnable接口
  2. 重写run方法,
  3. 创建自己类的对象,
  4. 创建Thread对象开启线程

示例:

package text_1;public class demo_2 {public static void main(String[] args) {/**   第二种实现方式:*   自定义一个类实现Runnable接口*   重写run方法,*   创建自己类的对象,*   创建Thread对象开启线程** */MyRun mr=new MyRun();Thread t1=new Thread(mr);Thread t2=new Thread(mr);t1.setName("芜湖");t2.setName("呀呼");t1.start();t2.start();}
}
class MyRun implements Runnable{@Overridepublic void run() {Thread thread = Thread.currentThread(); // 获取当前线程的对象for (int i = 0; i < 10; i++) {System.out.println(thread.getName()+ "爱坤");}}
}

只所以能通过这中方式创建线程,是因为Thread类就是Runnable接口的实现类。

在这里插入图片描述

且在Thread类中的构造方法中有Runnable的实例,使用这种构造方法就可以将Runnable实例与Thread实例相关联,也就是说,使用这种构造方法后,Thread类调用的run方法就是Runnable中的run方法。
在这里插入图片描述




二、线程的生命周期

在这里插入图片描述




三、操作线程的方法

操作线程的方法有很多,这些方法可以使得线程从某种状态过度到另一种状态。



1、线程的休眠

sleep方法
在这里插入图片描述

该方法使得当前线程在指定的时代内不会进入就绪状态。
该方法是被static修饰的,所以可以直接使用类名调用。

示例:

package text_2;public class demo_1 {public static void main(String[] args) {MyThread mt1 = new MyThread();mt1.start();}
}class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 10; i++) {try {// 以毫秒为单位Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("芜湖");}}
}


2、线程的加入

join方法
在Java多线程编程中,join方法是一个非常重要的概念。它用于确保主线程等待其他线程完成其任务后再继续执行。当一个线程调用另一个线程的join方法时,调用线程会阻塞,直到被调用线程结束执行。

join方法通常在创建线程时使用,以确保主线程不会在子线程完成前结束。这有助于防止数据竞争和其他并发问题。

在这里插入图片描述

示例:

package text_2;public class demo_1 {public static void main(String[] args) throws InterruptedException {MyThread mt1 = new MyThread();MyThread mt2 = new MyThread();mt1.setName("wuhu");mt2.setName("yahu");mt1.start();mt1.join();mt2.start();}
}class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 4; i++) {try {// 以毫秒为单位Thread.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(getName());}}
}


3、线程的礼让

在Java中,线程礼让是指在线程A和线程B执行的时候,线程B由于某种原因需要先一步执行,那么可以对线程A执行yield方法,先让线程B执行一步。请注意,这里和join方法不一样,join方法是将CPU资源全都分出,直到线程B执行完,而yield只会让出一步。


4、线程的优先级

在Java中,线程的优先级是一个整数,范围从1(最低优先级)到10(最高优先级)。默认情况下,新创建的线程的优先级为5。线程优先级越小,线程越优先被执行;线程优先级越大,线程越后被执行。可以通过Thread类的setPriority(int)方法来设置线程的优先级。

请注意,如果优先级相同的线程同时存在,那么会按照提交顺序(也就是代码编写顺序)执行的方式。

package text_2;public class demo_2 {public static void main(String[] args) {/**   设置优先级   :setPriority()*   获取优先级   : get*   守护线程     :setDaemon(boolean)*               细节:守护线程会在所有非守护线程结束后结束* */
//        System.out.println(Thread.currentThread().getPriority());MyThread_2 mt1 = new MyThread_2();MyThread_2 mt2 = new MyThread_2();mt1.setName("芜湖");mt2.setName("呀呼");System.out.println(mt1.getPriority());  // 获取当前优先级mt1.setPriority(10);System.out.println(mt1.getPriority());  // 获取当前优先级//        MyThread_3 mt3 = new MyThread_3();
//        mt3.setName("run");
//        mt3.setDaemon(true);mt1.start();mt2.start();}
}class MyThread_2 extends Thread{@Overridepublic void run() {Thread thread = Thread.currentThread();for (int i = 0; i < 10; i++) {System.out.println(thread.getName()+"i");}}
}
class MyThread_3 extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName()+""+i);}}
}



四、线程同步

Java线程同步是一个非常重要的概念,主要用于解决多线程并发控制问题。当多个线程同时操作一个可共享的资源变量时,可能会产生数据不准确和相互冲突的问题。为了解决这些问题,Java提供了多种同步机制,包括synchronized关键字、Lock接口和AtomicInteger类等。

其中,synchronized关键字是最基本的同步机制,可以用于方法或代码块的同步。当一个线程在执行一个synchronized方法时,其他试图访问该对象的线程将被阻塞,直到第一个线程执行完毕。这样可以确保同一时间只有一个线程可以访问共享资源,避免了数据不一致和程序异常的问题。

一般情况:窗口售票

package text_3;public class demo {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.setName("窗口一");t2.setName("窗口二");t3.setName("窗口三");t1.start();t2.start();t3.start();}
}class MyThread extends Thread {static int ticket = 0;@Overridepublic void run() {while (true) {// 同步线程:线程锁(锁对象) 需要注意的是锁对象一定是要唯一的try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}if (ticket < 100) {++ticket;System.out.println(getName() + "正在卖第" + ticket + "张票");} else {break;}}}
}

运行结果:
在这里插入图片描述


通过运行结果,我们可以看出没有加线程同步的情况,多个线程对同一资源的访问,因为系统cpu轮转的情况,某一线程可能已经售出了某张票,但是另一个线程也在售出这张票,所以导致了重复售出的情况。


线程同步机制

线程同步机制是Java多线程编程中的重要概念,主要用于解决多线程并发控制问题。线程同步机制可以让多个线程按照一定的顺序执行,避免出现数据不一致和相互冲突的问题。Java中实现线程同步的方式有多种,包括synchronized关键字、Lock接口、信号量Semaphore、倒计时门闩CountDownLatch、循环栅栏CyclicBarrier和闭包等。

其中,synchronized关键字是最基本的线程同步机制之一,可以用于方法或代码块的同步。当一个线程在执行一个synchronized方法时,其他试图访问该对象的线程将被阻塞,直到第一个线程执行完毕。这样可以确保同一时间只有一个线程可以访问共享资源,避免了数据不一致和程序异常的问题。

需要注意的是,使用synchronized块进行同步线程时,同步代码块的对象一定需要是唯一的。

同步代码块改进

package text_3;public class demo {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.setName("窗口一");t2.setName("窗口二");t3.setName("窗口三");t1.start();t2.start();t3.start();}
}class MyThread extends Thread {static int ticket = 0;@Overridepublic void run() {while (true) {// 同步线程:线程锁(锁对象) 需要注意的是锁对象一定是要唯一的synchronized (MyThread.class) {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}if (ticket < 100) {++ticket;System.out.println(getName() + "正在卖第" + ticket + "张票");} else {break;}}}}
}

运行结果: 杜绝了重复票的情况

在这里插入图片描述




End

本文如有错误,望指正。

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

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

相关文章

Windows挂载NFS

ubuntu开启nfs 安装 sudo apt install nfs-kernel-server编辑 /etc/exports /data/share *(rw,no_root_squash)重启服务 sudo systemctl restart nfs-server.service验证 showmount -e localhostwindows连接NFS 选择控制面板 > 程序 > 启用或关闭 Windows 功能 添加…

C++,请问为什么力扣题704中,取数组的长度,使用sizeof()/4在运行时候没有报错,但是提交之后报数组越界的错误呢?使用size又可以了

C,请问为什么力扣题704中&#xff0c;取数组的长度&#xff0c;使用sizeof()/4在运行时候没有报错&#xff0c;但是提交之后报数组越界的错误呢&#xff1f;使用size又可以了 在C中&#xff0c; sizeof() 运算符用于获取一个对象或类型的字节大小。在使用 sizeof() 时&#xf…

【Go】EasyJson使用

EasyJson是Go语言中对象序列化与反序列化的工具&#xff0c;类似Java中的fastjson和Jackson&#xff0c;能快速对对象进行序列化和反序列化&#xff0c;本次介绍一下使用方法。 版本信息&#xff1a; go1.20.2 1&#xff0c;获取源码 # go get go get -u github.com/mailru…

centos用户相关命令

添加用户命令&#xff1a; adduser tony.wang useradd tony.wang 这两个命令都行&#xff0c;如果已经添加了会提示已经存在。 设置密码&#xff1a; passwd tony.wang 如果需要加入sudo组&#xff1a; usermod -aG sudo tony.wang 这个命令我在CentOS7上是不行的&#x…

理解射频中常用的史密斯圆图(Smith Chart)

理解射频中常用的史密斯圆图&#xff08;Smith Chart&#xff09; 工程中常用史密斯圆图表示射频器件端口的回波损耗 Γ \Gamma Γ. 回波损耗 回波损耗&#xff0c;又称器件端口的反射系数&#xff0c;反映了器件的端口阻抗 Z_{1L} 与传输线阻抗 Z 0 Z_0 Z0​ 之间的匹配&…

入耳耳机对耳朵有损害吗?戴哪种耳机不伤耳朵听力?

长时间佩戴入耳式耳机会对耳朵造成伤害的&#xff0c;建议佩戴骨传导耳机&#xff0c;不入耳佩戴使用更健康。 为什么推荐使用骨传导耳机&#xff0c;首先因为入耳式耳机需要塞入耳道内佩戴&#xff0c;长时间使用会使耳道内滋生细菌&#xff0c;容易引发耳道疾病&#xff0c;…

Python爬虫入门:如何设置代理IP进行网络爬取

目录 前言 一、获取代理IP 1.1 获取免费代理IP 1.2 验证代理IP 二、设置代理IP 三、使用代理IP进行网络爬取 四、总结 前言 在进行网络爬取时&#xff0c;经常会遇到一些反爬虫的措施&#xff0c;比如IP封锁、限制访问频率等。为了解决这些问题&#xff0c;我们可以使用…

软件测评中心▏软件集成测试和功能测试之间的区别和联系简析

软件集成测试是在软件开发周期的后期阶段进行的测试活动&#xff0c;旨在验证系统各个组件之间的接口和交互是否正常工作。而功能测试是一种验证软件系统是否按照需求规格说明书所规定的功能进行正确实现的测试。接下来&#xff0c;我们来分别探讨一下软件集成测试和功能测试有…

windows系统用nginx部署web应用

要在Windows系统上使用Nginx进行本地部署和运行Web应用程序&#xff0c;可以按照以下步骤进行操作&#xff1a; 1.首先下载nginx&#xff0c;需要去nginx官网&#xff1a; nginx: download 下载最新版本的&#xff1a; 2.解压缩Nginx&#xff1a;找个磁盘位置&#xff0c;新…

C\C++:原子计数操作 之__syn_fetch_and_add性能研究

背景 首先在多线程环境中&#xff0c;多线程计数操作&#xff0c;共享状态或者统计相关时间次数等&#xff0c;这些需要在多线程之间共享变量和修改变量&#xff0c;如此就需要在多线程间对该变量进行互斥操作和访问。 但是如果我们要维护一个全局的线程安全的 int 类型变量 co…

Vue3生命周期函数(简述题)

1.图示 2.说明 3.补充 1.在vue3组合式API中&#xff0c;我们需要将生命周期函数先导入&#xff0c;然后才能使用。 import {onMounted} from vue2.beforeCreate和created被setup()方法所代替

re:Invent 构建未来:云计算生成式 AI 诞生科技新局面

文章目录 前言什么是云计算云计算类型亚马逊云科技云计算最多的功能最大的客户和合作伙伴社区最安全最快的创新速度最成熟的运营专业能力 什么是生成式 AI如何使用生成式 AI后记 前言 在科技发展的滚滚浪潮中&#xff0c;我们见证了云计算的崛起和生成式 AI 的突破&#xff0c…

基于ssm亚盛汽车配件销售业绩管理系统

摘 要 如今的信息时代&#xff0c;对信息的共享性&#xff0c;信息的流通性有着较高要求&#xff0c;因此传统管理方式就不适合。为了让亚盛汽车配件销售信息的管理模式进行升级&#xff0c;也为了更好的维护亚盛汽车配件销售信息&#xff0c;亚盛汽车配件销售业绩管理系统的开…

RNN-T Training,RNN-T模型训练详解——语音信号处理学习(三)(选修三)

参考文献&#xff1a; Speech Recognition (option) - RNN-T Training哔哩哔哩bilibili 2020 年 3月 新番 李宏毅 人类语言处理 独家笔记 Alignment Train - 8 - 知乎 (zhihu.com) 本次省略所有引用论文 目录 一、如何将 Alignment 概率加和 对齐方式概率如何计算 概率加和计…

C#中 怎么检测Tcp网线断开?

在 C# 中&#xff0c;如果使用 TcpClient 或 TcpListener 这样的套接字进行通信&#xff0c;并且网络连接断开&#xff0c;不发送心跳是无法立即检测到断开的。这是因为 TCP 协议本身没有内置的机制来检测连接是否还活动中。 当使用 TCP 进行通信时&#xff0c;通常是通过发送…

PyQt6第一个程序HelloWorld实现

锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计12条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版…

LeetCode63. Unique Paths II

文章目录 一、题目二、题解 一、题目 You are given an m x n integer array grid. There is a robot initially located at the top-left corner (i.e., grid[0][0]). The robot tries to move to the bottom-right corner (i.e., grid[m - 1][n - 1]). The robot can only m…

three.js球体实现

作者&#xff1a;baekpcyyy&#x1f41f; 使用three.js渲染出可以调节大小的立方体 1.搭建开发环境 1.首先新建文件夹用vsc打开项目终端 2.执行npm init -y 创建配置文件夹 3.执行npm i three0.152 安装three.js依赖 4.执行npm I vite -D 安装 Vite 作为开发依赖 5.根…

网络协议系列:TCP三次握手,四次挥手的全过程,为什么需要三次握手,四次挥手

TCP三次握手&#xff0c;四次挥手的全过程&#xff0c;为什么需要三次握手&#xff0c;四次挥手 一. TCP三次握手&#xff0c;四次挥手的全过程&#xff0c;为什么需要三次握手&#xff0c;四次挥手前言TCP协议的介绍三次握手三次握手流程&#xff1a;1. A 的 TCP 向 B 发送 连…

【嵌入式Linux开发一路清障-连载04】虚拟机VirtualBox7.0安装Ubuntu22.04后挂载Windows平台共享文件夹

虚拟机安装Ubuntu22.04后挂载Windows平台共享文件夹 障碍07-虚拟机VirtualBox7.0完装完Ubuntu22.04后&#xff0c;无法成功挂载Windows平台中共享文件夹&#xff0c;无法访问电脑中的各类重要文件&#xff0c;我该怎么办&#xff1f;一、问题的模样&#xff1a;VirtualBox7.0设…