多线程基础说明【基础篇】

目录

🌭1.相关概念 

🍿2.创建和启动线程 

🥞3.线程安全

🧈4.死锁

🥓5.线程通信的方法


1.相关概念

1.1程序

为完成特定任务,用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。

1.2进程

  • 程序的一次执行过程,或是正在内存中运行的应用程序。
  • 每个进程都有一个独立的内存空间。
  • 程序是静态的,进程是动态的。
  • 进程是操作系统调度和分配资源的最小单位。

1.3线程

  • 进程可进一步细化为线程,是程序内部的一条执行路径。
  • 一个进程中至少有一个线程。
  • 一个进程同一时间若 并行 执行多个线程,就是支持多线程的。
  • 线程作为 CPU调度和执行的最小单位。

1.4并行

  • 指两个或多个事件在 同一时刻 发生(同时发生)。
  • 指在同一时刻,有多条指令 在多个CPU 上 同时 执行。

比如:多个人同时做不同的事。

1.5并发 

  • 指两个或多个事件在同一个时间段内发生。
  • 即在一段时间内,有多条指令在单个CPU上快速轮换、交替执行,使得在宏观上目有名个进程同时执行的效果

2.创建和启动线程 

Java语言的JvM允许程序运行多个线程,使用java.lang.Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例

2.1继承Thread类

  • 1.创建一个类,继承Thread
  • 2.重写Thread类的run()方法,将此线程要执行的操作,声明在此方法中
  • 3.创建当前Thread的子类的对象
  • 4.通过对象调用start(), start():1.启动线程,2.调用当前线程的run()方法
public class MyTest {
    public static void main(String[] args) {

        //3.创建当前Thread的子类的对象
        PrintNumber p1 = new PrintNumber();


        //4.调用start()方法
        p1.start();

        //main()所在线程执行的操作
        for (int i=0;i<=100;i++){
            if (i%2==0){
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }


}

//1.创建子类,继承Thread
class PrintNumber extends Thread {
    //2.重写run()方法
    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
}
  • 不能使用p1.run()替换p1.start()的调用 
  • 不能让已经执行start()的线程,再次执行start(),否则报错,应重新创建对象再调用start()

 2.2实现Runnable接口

  • 1.创建一个类,实现Runnable接口
  • 2.实现接口中的run()方法,将此线程要执行的操作,写在run()方法中
  • 3.创建当前实现类的对象
  • 4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的实例
  • 5.Thread类的实例调用start() 
public class RunnableTest {
    public static void main(String[] args) {

        //3.创建实现类的对象
        Number n1 = new Number();

        //4.将对象传递到Thread的构造器中
        Thread thread = new Thread(n1);

        //5.调用start()方法
        thread.start();

    }
}



//1.创建类,实现Runnable接口
class Number implements Runnable {
    //2.实现run()方法,并将要执行的操作,写在run()方法中
    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() +"-偶数:"+i);
            }
        }
    }
}

也可以使用匿名实现RUnnable接口,

new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 100; i++) {
                    if (i % 2 == 0) {
                        System.out.println(Thread.currentThread().getName() + "-偶数:" + i);
                    }
                }
            }
        }).start();

使用Runnable的好处:

  • 1.实现的方式,避免类的单继承的局限性
  • 2.更适合处理共享数据的问题
  • 3.实现了代码和数据的分类

2.3常用方法

  • 1.start():1.启动线程 2.调用线程的run()方法
  • 2.run():将线程要执行的操作,写在run()方法中 
  • 3.currentThread():获取当前代码执行所对应的线程
  • 4.sleep():静态方法,睡眠指定毫秒数
  • 5.yield():静态方法,释放cpu的执行权
  • 6.jion():在线程A中通过线程B调用jion(),线程A进入阻塞状态直到线程B执行完成。
  • 7.isAlive():判断当前线程是否存活 
  •  2.4.线程的生命周期

3.线程安全

3.1问题

模拟三个窗口卖票,在第一个线程未结束的同时,其他线程参与进来,会出现重复票和错票

3.2解决

必须保证一个线程a在操作共享数据的过程中,其他线必须等待,直到线程a操作结束,其他线程才可以继续操作

3.3线程的同步机制

  • 方式一:同步代码块

synchronized (同步监视器){

      操作共享数据的代码

}

  1. 共享数据:多个线程需要操作的数据。
  2. 同步监视器:俗称 锁  。哪个线程获取了锁,哪个线程就能执行代码块。
  3. 同步监视器可以使用任何一个类的对象充当,当多个线程必须共用同一个同步监视器。
public class WindowTest {

    public static void main(String[] args) {
        SaleTicket saleTicket = new SaleTicket();

        Thread t1 = new Thread(saleTicket);
        Thread t2 = new Thread(saleTicket);
        Thread t3 = new Thread(saleTicket);

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");


        t1.start();
        t2.start();
        t3.start();
    }

}


class SaleTicket implements Runnable {

    int ticket = 100;
    Object object = new Object();

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (object) {
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + "售票,票号:" + ticket);
                    ticket--;
                } else {
                    System.out.println(Thread.currentThread().getName()+"票数不足!");
                    break;
                }
            }
        }

    }
}
  • 方式二:同步方法
public class WindowTest {

    public static void main(String[] args) {
        SaleTicket saleTicket = new SaleTicket();

        Thread t1 = new Thread(saleTicket);
        Thread t2 = new Thread(saleTicket);
        Thread t3 = new Thread(saleTicket);

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");


        t1.start();
        t2.start();
        t3.start();
    }

}


class SaleTicket implements Runnable {

    static int ticket = 100;
    static Object object = new Object();
    Boolean isFlag=true;

    @Override
    public void run() {
        while (isFlag) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
                show();

        }
    }

    public synchronized void show(){ //此时的同步监视器就是this,即代码中的saleTicket,唯一的
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "售票,票号:" + ticket);
            ticket--;
        }else {
            System.out.println(Thread.currentThread().getName()+"票数不足");
            isFlag=false;
        }
    }
}

注:

非静态的同步方法,默认同步监视器是this

静态的同步方法,默认同步监视器是当前类本身

synchronized

好处:解决了线程安全问题

弊端:在操作共享数据时,多线程其实是串行执行的,性能较低 

4.死锁

不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。

4.1原因

  • 互斥条件
  • 占用且等待
  • 不可抢夺(或不可抢占)
  • 循环等待

4.2解决

  • 针对条件1:互斥条件基本上无法被破坏。因为线程需要通过互斥解决安全问题。
  • 针对条件2:可以考虑一次性申请所有所需的资源,这样就不存在等待的问题。
  • 针对条件3:占用部分资源的线程在进一步申请其他资源时,如果申请不到,就主动释放掉已经占用的资源。
  • 针对条件4:可以将资源改为线性顺序。申请资源时,先申请序号较小的,这样避免循环等待问题。 

5.线程通信的方法

  • wait():线程一旦执行此方法,就进入等待状态。同时,会释放对同步监视器的调用
  • notify():一但执行此方法,就会唤醒wait()的线程中优先级最高的那个线程,如果被wait()唤醒的线程优先级相同,则随即唤醒一个
  • notifyAll():一但执行此方法,就唤醒所有被wait的线程
public class AdTest {

    public static void main(String[] args) {
        PrintNumbers printNumbers = new PrintNumbers();

        Thread thread1 = new Thread(printNumbers, "线程1");
        Thread thread2 = new Thread(printNumbers, "线程2");

        thread1.start();
        thread2.start();
    }

}

class PrintNumbers implements Runnable {

    private int number = 1;

    @Override
    public void run() {

        while (true) {
            synchronized (this) {
                notify();
                if (number <= 100) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + number);
                    number++;

                    try {
                        wait();//线程执行此方法,进入等待状态,同时释放同步监视器的调用
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    break;
                }
            }
        }
    }
}

wait()  VS  sleep()

相同点:一旦执行,当前线程都会阻塞

不同点:声明的位置、使用场景、sleep不会释放同步监视器、阻塞的方式

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

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

相关文章

数据结构二叉树顺序结构——堆的实现

二叉树顺序结构——堆的实现 结构体的创建以及接口函数结构体的创建堆的初始化交换函数堆的插入向上调整删除向下调整返回堆的个数返回堆顶数据判断堆是否为空 该文章以大堆作为研究对象 结构体的创建以及接口函数 typedef int HPDateType;//定义动态数组的数据类型 typedef s…

Spring Cloud学习

1、什么是SpringCloud Spring cloud 流应用程序启动器是基于 Spring Boot 的 Spring 集成应用程序&#xff0c;提供与外部系统的集成。Spring cloud Task&#xff0c;一个生命周期短暂的微服务框架&#xff0c;用于快速构建执行有限数据处理的应用程序。Spring cloud 流应用程…

Oracle ADG相关介绍

文章目录 一、ADG原理1、ADG介绍2、ADG搭建流程 二、ADG相关参数三、增量修复 一、ADG原理 1、ADG介绍 Oracle ADG&#xff08;Advanced Data Guard&#xff09;是Oracle数据库的一项高可用和灾难恢复技术&#xff0c;它通过将数据保持在物理备库中来提供数据保护和容灾能力。…

Odoo系统安装部署并结合内网穿透实现固定域名访问本地ERP系统

文章目录 前言1. 下载安装Odoo&#xff1a;2. 实现公网访问Odoo本地系统&#xff1a;3. 固定域名访问Odoo本地系统 前言 Odoo是全球流行的开源企业管理套件&#xff0c;是一个一站式全功能ERP及电商平台。 开源性质&#xff1a;Odoo是一个开源的ERP软件&#xff0c;这意味着企…

C++ 游戏飞机大战, 字符型的

//#define _CRT_SECURE_NO_WARNINGS 1 用于禁止不安全函数的警告 #include<iostream> #include<stdlib.h> #include<string> #include<conio.h> #include<Windows.h> #include<time.h> #include <graphics.h> using namespace std;…

Python爬虫-付费代理推荐和使用

付费代理的使用 相对免费代理来说&#xff0c;付费代理的稳定性更高。本节将介绍爬虫付费代理的相关使用过程。 1. 付费代理分类 付费代理分为两类&#xff1a; 一类提供接口获取海量代理&#xff0c;按天或者按量收费&#xff0c;如讯代理。 一类搭建了代理隧道&#xff0…

一元函数微分学——刷题(22

目录 1.题目&#xff1a;2.解题思路和步骤&#xff1a;3.总结&#xff1a;小结&#xff1a; 1.题目&#xff1a; 2.解题思路和步骤&#xff1a; 由于是极坐标方程&#xff0c;所以这个式子一定成立&#xff1a; 然后代入r即可变为参数方程的求导&#xff1a; 3.总结&#xff…

52.仿简道云公式函数实战-文本函数-LEFT

1. LEFT函数 从一个文本字符串的第一个字符开始返回指定个数的字符。 2. 函数用法 LEFT(text,[num_chars]) 3. 函数示例 从一个文本字符串的第一个字符开始返回指定个数的字符。 4. 代码实战 首先我们在function包下创建text包&#xff0c;在text包下创建LeftFunction类…

POST参数里加号+变成空格的问题处理

今天遇到个这样的问题&#xff0c;从前端传到后端的加密报文&#xff0c;里面包含了号&#xff0c;但在后端日志输出看出&#xff0c;变成空格。这个是由于经过RSA加密后引起的 解决办法&#xff1a; 1.前端转码&#xff1a;使用encodeURIComponent对参数进行转码 2.后端解码…

msvcp110.dll找不到的处理方法,一键修复msvcp110.dll文件

如果你遭遇到了“msvcp110.dll文件丢失”的现象&#xff0c;那就要引起足够的重视&#xff0c;因为这通常意味着你的电脑上某些依赖此DLL文件的应用程序将无法正常启动。msvcp110.dll是许多软件中必须的组件&#xff0c;一旦发生丢失&#xff0c;影响的不仅是单个程序&#xff…

Java SpringBoot 整合 MyBatis 小案例

Java SpringBoot 整合 MyBatis 小案例 基础配置&#xff08;注意版本号&#xff0c;容易报错&#xff09; pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http…

武汉灰京文化:中国手游行业新技术的涌现与产业链的完善

中国手游行业正迎来新技术的涌现&#xff0c;如虚拟现实&#xff08;VR&#xff09;、增强现实&#xff08;AR&#xff09;和人工智能&#xff08;AI&#xff09;。这些技术为游戏提供了全新的可能性&#xff0c;扩展了游戏的玩法和体验。例如&#xff0c;VR技术可以让玩家沉浸…

卖家横扫海外露营市场的机会来了,赛盈分销预测2024年消费者新需求

甲辰龙年开篇&#xff0c;就要迎来国外野营浪潮了&#xff0c;希望点开这篇推送的你&#xff0c;红红火火、热辣滚烫一整年。每年的3月份&#xff0c;海外用户对露营设备的搜索开始迅速增长。今天和大家聊聊露营市场出海的一些布局方向。 全球露营商品的市场规模愈发壮大&#…

Maven jar 的查找及依赖版本确定

关于 jar 的查找&#xff0c;及使用版本的确定&#xff0c;及依赖的版本确认&#xff0c;避免 jar 冲突或版本不兼容 在使用 maven 构建项目时&#xff0c;需要的 jar 可以通过在 https://mvnrepository.com/ 可以找到部分需要的依赖&#xff0c;这里以查找 mybatis 依赖为例&…

再次委托|工科背景老师赴美国斯坦福大学自费访学

工科背景的I老师&#xff0c;几年前曾通过我们获得美国哈佛大学医学院的无薪博士后职位&#xff0c;从事医工交叉学科研究。回国完成2年服务期后&#xff0c;I老师再次委托并仍希望去美国顶尖高校&#xff0c;最终我们落实了世界名校斯坦福大学的访问学者职位&#xff0c;满足了…

微信小程序自制动态导航栏

写在前面 关于微信小程序导航栏的问题以及解决办法我已经在先前的文章中有提到&#xff0c;点击下面的链接即可跳转~ &#x1f90f;微信小程序自定义的导航栏&#x1f90f; 在这篇文章中我们需要做一个这样的导航栏&#xff01;先上效果图 &#x1f447;&#x1f447;&#x1f…

HTTP/HTTPS协议

什么是HTTP协议 HTTP被称为超文本传输协议(里面不仅仅可以是字符串,还可以是图片,特殊字符等),这是一种应用非常广泛的应用层协议. HTTP协议诞生于1991年,现在是最主流使用的一种应用层协议.它从诞生到现在为止迭代了多个版本. 但目前最主流使用的还是HTTP1.1和HTTP2.0. HTTP协…

大学餐厅菜品推荐和点评系统设计与实现

**&#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;**一 、设计说明 1.1 研究背景…

Opencv(2)深浅拷贝与基本绘图(c++python

Opencv(2)深浅拷贝与基本绘图 文章目录 Opencv(2)深浅拷贝与基本绘图三、深浅拷贝四、HSV色域(1).意义(2).cvtColor()(3).inRange()(4).适应光线 三、深浅拷贝 浅拷贝是指当图像之间进行赋值时&#xff0c;图像数据并未发生复制&#xff0c;而是两个对象都指向同一块内存块。 …

Amazon Generative AI | 基于 Amazon 扩散模型原理的代码实践之采样篇

以前通过论文介绍 Amazon 生成式 AI 和大语言模型&#xff08;LLMs&#xff09;的主要原理之外&#xff0c;在代码实践环节主要还是局限于是引入预训练模型、在预训练模型基础上做微调、使用 API 等等。很多开发人员觉得还不过瘾&#xff0c;希望内容可以更加深入。因此&#x…