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

news2024/11/23 21:40:36

多线程

    • 前言
    • 一、线程的创建
      • 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{
    @Override
    public 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{
    @Override
    public 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{
    @Override
    public 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{
    @Override
    public 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{
    @Override
    public void run() {
        Thread thread = Thread.currentThread();
        for (int i = 0; i < 10; i++) {
            System.out.println(thread.getName()+"i");
        }
    }
}
class MyThread_3 extends Thread{
    @Override
    public 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;
    @Override
    public 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;
    @Override
    public 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.coloradmin.cn/o/1266109.html

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

相关文章

MSB3541 Files 的值“<<<<<<< HEAD”无效。路径中具有非法字符。

MSB3541 Files 的值“<<<<<<< HEAD”无效。路径中具有非法字符。 一般来说出现这个问题是因为使用git版本控制工具合并代码出现了问题&#xff0c;想要解决也很简单。 如图点击错误后定位到文件&#xff0c;发现也没有什么问题。 根据错误后边的提示&a…

GoWeb学习-第二天

文章目录 从零开始学Go web——第二天一、安装Go语言二、建立web目录2.1 创建GO语言包目录2.2 创建Go web文件 三、编译并运行Go web应用3.1 编译并运行3.2 查看结果 从零开始学Go web——第二天 ​ 第一天我们了解了与web息息相关的HTTP协议&#xff0c;聊了聊Go与web的关系等…

深度解读:为什么要做数据合规?如何做到数据合规?

数据资源“入表”在即&#xff0c;企业更需筑牢数据合规防线。但企业主企业购买数据、获取数据到底是否合法合规&#xff0c;入表如何防范合规风险&#xff1f;上周三&#xff0c;亿信华辰邀请到北京鑫诺律师事务所高级合伙人、管委会副主任武婕将和大家分享《数据入表法律合规…

扩散模型DDPM学习笔记

扩散模型DDPM 文章目录 扩散模型DDPM如何运作基本概念训练过程推理过程&#xff1a; 目标损失函数推导评估标准 论文地址&#xff1a; Denoising Diffusion Probabilistic Models (DDPM) 如何运作 ​ 从guassian distribution进行采样得到一个噪声的图片&#xff0c;图片大小…

使字符串的单词倒序输出表示

题目 任务描述 本关任务&#xff1a;请实现函数 revWordoder&#xff0c;能够将 pa 指向的单词表字符串中的所有单词&#xff0c;按相反顺序放入 pb&#xff0c;同时去除多余的空格&#xff0c;单词之间只留一个空格. 例如 pa 中为 red blue, 则调用函数后&#xff0c;pb 中为b…

如何通过Portal实现消息集成

在数字化时代浪潮下&#xff0c;信息的流通与交互已变得至关重要&#xff0c;不论是在企业内部日常协作&#xff0c;还是与外部客户的紧密沟通&#xff0c;信息的快速、准确、实时传递都成为了确保业务顺畅进行的关键因素、决策精准的核心要素。 为了满足这种日益增长的需求&a…

学生护眼灯怎么选?2023备考护眼台灯推荐

近期&#xff0c;许多“护眼台灯是否是智商税”的帖子频繁出现&#xff0c;引起了许多群众的关注&#xff0c;作为一名护眼台灯资深使用者&#xff0c;在这里声明一下&#xff0c;护眼台灯绝对不是智商税。护眼台灯是通过调节光线亮度和色温&#xff0c;降低蓝光辐射&#xff0…

苹果提醒事项怎么用?几个简单步骤就能学会!

苹果提醒事项可以帮助你轻松管理待办事项&#xff0c;让你更好地安排自己的时间和工作。但是&#xff0c;有些小伙伴可能对如何使用这个功能还有一些疑问。苹果提醒事项怎么用&#xff1f;不要担心&#xff0c;小编将为大家提供使用提醒事项的方法&#xff0c;帮助你学会如何使…

代码随想录算法训练营第四十九天【动态规划part10】 | 121. 买卖股票的最佳时机、122.买卖股票的最佳时机II

121. 买卖股票的最佳时机 题目链接&#xff1a; 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 求解思路&#xff1a; 动规五部曲 确定dp数组及其下标含义&#xff1a;使用一个二维数组dp[i][2]&#xff0c;dp[i][0]代表持有股票的最大收益&…

【VRTK】【VR开发】【Unity】9-瞬移

课程配套学习资源下载 https://download.csdn.net/download/weixin_41697242/88485426?spm=1001.2014.3001.5503 【移动的种类】 瞬移只是VR中移动的一种种类,其它还有连续移动,物理移动,摔臂移动等等。 瞬移自身也有多个分类,本篇介绍: 即时瞬移冲刺瞬移定点瞬移【瞬…

一篇教会你java内存图怎么画

首先我们要知道&#xff1a; 线程的本质是栈&#xff1b;程序执行时&#xff0c;在java栈中&#xff0c;成立一个线程栈&#xff0c;调用方法时方法不断压栈出栈&#xff0c;这个压栈出栈的过程就是线程执行的过程。方法执行 拷贝入栈 &#xff0c;执行完成 出栈&#xff0c;从…

leetcode刷题详解十一

⭕️583. 两个字符串的删除操作 思路&#xff1a;核心代码就是最长公共子序列&#xff0c;但是需要注意的是结果 就是如果说公共子序列为0&#xff0c;则需要两个字符串长度的才行 如果有&#xff0c;就是 n m ∗ 2 d p [ n ] [ m ] nm*2dp[n][m] nm∗2dp[n][m] int minDist…

企业人力资源公司抖音直播招聘断播怎么处理?

企业人力资源公司抖音直播招聘断播怎么处理&#xff1f; 最直接的处理方式就是进行抖音直播招聘报白&#xff0c;报白后在直播和视频中发布招聘和企业信息&#xff0c;不用担心被封禁和限制流量。 可以通过抖音直播进行招聘&#xff0c;也可以在视频中添加小程序&#xff0c;…

服务器数据恢复—服务器重装系统导致逻辑卷发生改变的数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌linux操作系统服务器&#xff0c;服务器中有4块SAS接口硬盘组建一组raid5阵列。服务器中存放的数据有数据库、办公文档、代码文件等。 服务器故障&检测&#xff1a; 服务器在运行过程中突然瘫痪&#xff0c;管理员对服务器进行了重装…

LINUX入门篇【11】---进程篇【3】---进程优先级,进程切换,进程调度

前言&#xff1a; 有了前面知识点的铺垫&#xff0c;本篇我们将围绕进程的三个方面来展开&#xff0c;即进程优先级&#xff0c;进程切换以及进程调度的问题&#xff0c;这里的进程调度其实本质就是CPU是如何去调度进程的。 进程优先级&#xff1a; 优先级的概念&#xff1a…

数字人透明屏幕是如何工作的?

数字人透明屏幕是一种令人兴奋的科技产品&#xff0c;它结合了人脸识别、全息影像技术以及透明屏幕&#xff0c;为人们带来了全新的互动体验。本文将详细介绍数字人透明屏幕的工作原理以及其应用场景。 工作原理 数字人透明屏幕的工作原理主要包括人脸识别和全息影像技术。人脸…

解决ant-design-vue中Select组件v-model值为空字符串不显示placeholder的bug

方法一&#xff1a; 1.找到node_modules/ant-design-vue/es/vc-select/SingleSelector.js文件 搜索renderPlacehoder方法 将其修改为 const renderPlacehoder () > {const list props.values.filter(val > val.value ! );if (list[0]) {return null}... }2.在此文件中…

浅谈硬件连通性测试几大优势

硬件连通性测试是确保硬件系统正常运行、提高系统可靠性和降低生产成本的关键步骤。在现代工程和制造中&#xff0c;将连通性测试纳入生产流程是一个明智的选择&#xff0c;有助于确保硬件产品的质量和性能达到最优水平。本文将介绍硬件连通性测试的主要优势有哪些! 一、提高系…

区域人员定位管理系统功能

人员定位管理系统是集计算机软硬件、信息采集处理、无线数据传输、网络数据通讯等技术多学科综合应用为一体的自动识别信息技术产品&#xff0c;实现对不同物体&#xff08;包括人&#xff09;在不同状态&#xff08;移动、静止&#xff09;下的自动识别&#xff0c;特定区域人…

深度学习框架配置

目录 1. 配置cuda环境 1.1. 安装cuda和cudnn 1.1.1. 显卡驱动配置 1.1.2. 下载安装cuda 1.1.3. 下载cudnn&#xff0c;将解压后文件复制到cuda目录下 1.2. 验证是否安装成功 2. 配置conda环境 2.1. 安装anaconda 2.2. conda换源 2.3. 创建conda环境 2.4. pip换源 3.…