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{
    @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

本文如有错误,望指正。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux中执行java命令报错:cannot execute binary file: Exec format error

网上很多文章 都是说操作系统和JDK&#xff0c;32位和64位不兼容问题 当你非常确定你的操作系统是64位&#xff0c;并且JDK也是64位的时候 或者非常确定你的操作系统是32位&#xff0c;并且JDK也是32位的时候 怎么办&#xff1f; 使用以下命令&#xff0c;查看你的操作系统…

IDEA插件推荐

今天给大家推荐一款IDEA插件&#xff1a;Apipost-Helper-2.0&#xff0c;支持三大功能&#xff1a;写完代码IDEA内一键生成API文档&#xff1b;写完代码IDEA内一键调试&#xff1b;生成API目录树&#xff0c;双击即可快速定位API定义的代码…非常好用&#xff01;而且完全免费&…

MySQL进阶-InnoDB引擎

✨作者&#xff1a;猫十二懿 ❤️‍&#x1f525;账号&#xff1a;CSDN 、掘金 、语雀 、Github &#x1f389;公众号&#xff1a;猫十二懿 一、InnoDB 逻辑存储引擎 InnoDB的逻辑存储结构如下图所示&#xff1a; 大小关系&#xff1a;表空间&#xff08;Tablespace&#xff0…

消息队列MQ

文章目录 同步通讯和异步通讯什么是MQ?一.RabbitMQ概述二.SpringAMQP1.Work Queue 工作队列2.发布订阅-Fanout Exchange3.发布订阅-DirectExchange4.发布订阅-TopicExchange 3.消息转换器 同步通讯和异步通讯 其实在之前的JAVASE中就已经在线程一章中接触过了同步和异步的概念…

实战:登录接口测试用例举例

以下是一些可能的登录接口测试用例&#xff08;使用Python编写的&#xff09;&#xff1a; 1. 测试正常情况下的登录接口&#xff1a; # 请求URL url "https://example.com/api/login" # 请求参数 username "testuser" password "testpassword&q…

数据治理框架和成熟度模型

数据治理成熟度模型 一个企业的数据治理能力越高&#xff0c;所享受到数据治理带来的价值也会越多&#xff0c;如增加收入、减少成本、降低风险等。于是&#xff0c;很多企业想要准确地评估本公司的数据治理能力&#xff0c;可以利用数据治理成熟度模型方法&#xff0c;包括 D…

摄影网站的技术 SEO:提示和最佳实践

摄影就是要给人留下良好的第一印象。如果你想在竞争中领先&#xff0c;摄影师的SEO是您可以采用的最佳营销方法之一。 我们都曾有过这样的经历&#xff1a;你建立了一个漂亮的作品集网站来吸引更多的业务。网站上线并在社交媒体上推广后&#xff0c;您就可以坐等了。网站访问量…

堆的应用(堆排序、Top-K问题)

文章目录 1 堆排序2 Top-K问题 1 堆排序 堆排序是一种基于二叉堆&#xff08;通常使用数组实现&#xff09;的排序算法。 它的基本思想是利用堆这种数据结构的性质&#xff0c;通过建立一个堆&#xff08;大堆或小堆&#xff09;&#xff0c;使得堆的根节点是所有节点中的最大值…

牛客 算法题 golang语言实现

题目 HJ101 输入整型数组和排序标识&#xff0c;对其元素按照升序或降序进行排序 描述 输入整型数组和排序标识&#xff0c;对其元素按照升序或降序进行排序数据范围&#xff1a; 1 ≤ &#xfffd; ≤ 10001≤n≤1000 &#xff0c;元素大小满足 0 ≤ &#xfffd; &#…

提升企业网络安全的得力助手——EventLog Analyzer网络日志管理

在当今数字化时代&#xff0c;企业的网络安全问题变得尤为重要。为了更好地应对日益增多的威胁和安全漏洞&#xff0c;企业需要一种高效的网络日志管理工具&#xff0c;EventLog Analyzer便是其中一款卓越的解决方案。 EventLog Analyzer EventLog Analyzer是一款综合性的网络…

探索短剧市场的商机:打造短视频平台的全方位指南

目前短剧市场蓬勃发展&#xff0c;上半年备案数远超电视剧&#xff0c;彰显了短剧小程序市场潜力巨大&#xff0c;商业价值巨大。用户对短小精悍娱乐内容的需求不断增加&#xff0c;而新兴市场中有限的短剧小程序正好能够迎合这一需求。 搭建短视频平台的关键步骤&#xff1a; …

GOAT:多模态、终身学习、平台无关的机器人通用导航系统

机器人应用中涉及到的核心技术包括&#xff1a;环境感知与理解、实时定位与建图、路径规划、行为控制等。GOAT通过多模态结合终生学习的方式让你的机器人可以在未知环境中搜索和导航到任何物体。小白也可以零门槛上手。 项目地址&#xff1a;https://theophilegervet.github.i…

性能优化的一般策略及方法

性能优化的一般策略及方法 在汽车嵌入式开发领域&#xff0c;性能优化始终是一个无法回避的问题&#xff1a; 座舱 HMI 想要实现更流畅的人机交互 通信中间件在给定的 CPU 资源下&#xff0c;追求更高的吞吐量 更一般的场景&#xff1a;嵌入式设备 CPU 资源告急&#xff0c;需…

Web前端开发技术:图像与多媒体文件

在现代的Web开发中&#xff0c;图像和多媒体文件在各种网站和应用程序中扮演着至关重要的角色。它们不仅能提供更丰富的内容&#xff0c;还能大大提高应用程序的吸引力和用户体验。本文将深入介绍一些关键的Web前端开发技术&#xff0c;这些技术将有助于开发者在处理图像和多媒…

【Python3】【力扣题】367. 有效的完全平方数

【力扣题】题目描述&#xff1a; 【Python3】代码&#xff1a; 1、解题思路&#xff1a;Python函数。num的平方根 或者 num的0.5次幂。 知识点&#xff1a;float.is_integer(...)&#xff1a;判断浮点数的值是否等于整数。也可以&#xff1a;浮点数.is_integer()。 pow(a,b)&…

JAVA多线程总结

一、概念&#xff1a; 1、什么是多任务 多任务就是在同一时间做多件事情&#xff0c;如边吃饭边玩手机等。看起来是多个任务都在做&#xff0c;本质上我们的大脑在同一时间依旧只做了一件件事情 2、什么是程序 程序是指令和数据的有序集合&#xff0c;其本身没有任…

“一键转换JPG到BMP:轻松优化图片管理的革命性工具“

亲爱的用户们&#xff0c;您是否曾经因为图片格式不兼容而感到烦恼&#xff1f;是否曾经为了转换图片格式而耗费大量时间&#xff1f;现在&#xff0c;我们为您带来了一款全新的图片转换工具&#xff0c;它可以轻松解决您的问题&#xff01; 首先&#xff0c;我们进入首助编辑高…

同旺科技 USB 转 RS-485 适配器 -- 隔离型

内附链接 1、USB 转 RS-485 适配器 隔离版主要特性有&#xff1a; ● 支持USB 2.0/3.0接口&#xff0c;并兼容USB 1.1接口&#xff1b; ● 支持USB总线供电&#xff1b; ● 支持Windows系统驱动&#xff0c;包含WIN10 / WIN11 系统32 / 64位&#xff1b; ● 支持Windows …

idea打开.class文件没有反编译

1 问题描述 新安装的idea开发工具&#xff0c;打开.class文件查看内容时发现没有将文件进行反编译&#xff0c;所以具体的代码实现看不到。如图所示&#xff1a; 尝试了各种办法解决&#xff0c;最终都没有解决我的问题&#xff0c;其他同事的idea开发工具都可以打开.class文件…

基于SpringBoot与Vue的增城高校二手物品交易系统

基于SpringBoot 与 Vue 的增城高校二手物品交易系统的设计与实现 摘要&#xff1a;随着生活水平和在校大学生消费能力的提高&#xff0c;学生用品的迭代速度越来越快&#xff0c;导致大量的闲置物品无法及时完成处理&#xff0c;而传统的线下摆摊等方式处理不仅效率低&#xf…