多线程(总结黑马程序员)

一、什么是线程?

  • 是一个程序内部的一条执行流程

多线程是什么?

  • 多条线程由CPU负责调度执行

多线程的创建方式一:继承Thread类

//1.继承Thread类
public class MyThread extends Thread {
    //2.必须重写run方法
    @Override
    public void run() {
        for (int i = 1; i <= 5 ; i++) {
            System.out.println("子线程MyThread输出 :" + i);
        }
    }
}



public class ThreadTest1 {
    //main方法是由一条默认的主线程负责执行
    public static void main(String[] args) {
        //3.创建MyThread线程类的对象代表一个线程
        Thread t = new MyThread();
        //4.启动线程(自动执行run方法)
        t.start();

        for (int i = 1; i <= 5 ; i++) {
            System.out.println("主线程main输出:" + i);
        }
    }
}

多线程的创建方式二:实现Runnable接口

//1.实现Runnable接口
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 1; i <= 5 ; i++) {
            System.out.println("子线程输出:" + i);
        }
    }
}

public class ThreadTest1 {
    public static void main(String[] args) {
        Runnable target = new MyRunnable();
        new Thread(target).start();

        for (int i = 1; i <= 5 ; i++) {
            System.out.println("主线程main输出:" + i);
        }
    }
}

匿名内部类的写法

public class ThreadTest1 {
    public static void main(String[] args) {
        //直接创建Runnable接口的匿名内部类
        Runnable target = new MyRunnable(){
            @Override
            public void run() {
                for (int i = 1; i <= 5 ; i++) {
                    System.out.println("子线程1输出:" + i);
                }
            }
        };
        new Thread(target).start();

        //简化形式1:
        new Thread(new MyRunnable(){
            @Override
            public void run() {
                for (int i = 1; i <= 5 ; i++) {
                    System.out.println("子线程2输出:" + i);
                }
            }
        }).start();

        //简化形式2
        new Thread(() -> {
                for (int i = 1; i <= 5 ; i++) {
                    System.out.println("子线程3

多线程的创建方式三:;利用Callable接口、FutureTask类来实现

//1.让这个类实现Callable接口
public class MyCallable implements Callable<String> {
    private int n;
    public MyCallable(int n) {
        this.n = n;
    }
    //2.重写call方法
    @Override
    public String call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= n ; i++) {
            sum += i;
        }
        return "线程求出了1-" + n + "的和是:" + sum;


    }
}

  public static void main(String[] args) throws ExecutionException, InterruptedException {
        //3.创建一个Callable对象
        Callable call = new MyCallable(100);
        //4.把Callable的对象封装成一个FutureTask对象
        //未来对象的作用?
        //1.是一个任务对象,实现了Runnable对象
        //2.可以在线程执行完毕之后,用未来任务对象调用get方法获取线程执行完毕后
        FutureTask<String> f1 = new FutureTask<>(call);
        new Thread(f1).start();

        Callable<String> call2 = new MyCallable(200);
        FutureTask<String> f2 = new FutureTask<>(call2);
        new Thread(f2).start();


        //6.获取线程执行完毕后返回的结果
        //注意:如果执行到这,假如上面的线程还没有执行完毕
        //这里的代码会暂停,等待上面线程执行完毕后才会获取结果
        String rs = f1.get();
        System.out.println(rs);

        String rs2 = f2.get();
        System.out.println(rs2 );

    }

Thread常用方法

public class ThreadTest1 {
    public static void main(String[] args) {
        MyThread t1 = new MyThread("1号线程");
        t1.start();
        System.out.println(t1.getName());

        MyThread t2 = new MyThread("2号线程");
        t2.start();
        System.out.println(t2.getName());

        //主线程对象的名字
        //哪个线程执行它,它就会得到哪个线程对象
        Thread m = Thread.currentThread();
        m.setName("最diao的线程");
        System.out.println(m.getName());

        for (int i = 1; i <= 5 ; i++) {
            System.out.println(m.getName() + "线程输出:" + i);
        }
    }
}


public class MyThread extends Thread {
    public MyThread(String name) {
        super(name); //为当前线程设置名字
    }

    @Override
    public void run() {
        Thread t = Thread.currentThread();
        for (int i = 1; i <= 3 ; i++) {
            System.out.println();
        }
    }
}

二、线程安全问题 

出现原因:

  • 存在多个线程同时执行
  • 同时访问一个共享资源
  • 存在修改该共享资源

取钱案例

需求:小明和小红有一个共同的账户,余额是10万元,模拟2人同时去取钱10万

  • 测试类
public class ThreadTest {
    public static void main(String[] args) {
        //1.创建一个账户对象,代表两个人的共享账户
        Account acc = new Account("ICBC-110", 100000);
        //2.创建两个线程,分别代表小明 小红,再去同一个账户对象中取钱10万
        new DrawThread(acc,"小明").start();
        new DrawThread(acc,"小红").start();
    }
}
  • 线程类
public class DrawThread extends Thread{
    private  Account acc;

    public DrawThread(Account acc,String name) {
        super(name);
        this.acc = acc;
    }

    @Override
    public void run() {
        //取钱
        acc.drawMoney(100000);
    }
}
  • 账户类
public class Account {

    private String cardId; //卡后
    private double money;  //账户余额

    public Account() {
    }

    public void drawMoney(double money) {
        //先搞清楚是谁来取钱
        String name = Thread.currentThread().getName();
        //1.判断余额是否够
        if(this.money >= money){
            System.out.println(name + "来取钱" + money + "成功!");
            this.money -= money;
            System.out.println(name + "取钱后,剩余余额:" + this.money);
        }else{
            System.out.println(name + "来取钱,余额不足");
        }
    }

    public Account(String cardId, double money) {
        this.cardId = cardId;
        this.money = money;
    }

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

}

三、线程同步

  • 解决线程安全问题的方案

线程同步的思想

  • 让多个线程实现先后依次访问共享资源

常见方案

  • 加锁:每次只允许一个线程加锁,加锁后才能进入访问,访问完毕后自动解锁,然后其他线程才能再加锁进来

方式1:同步代码块

  • 作用:把访问共享资源的核心代码给上锁,保证线程安全
  • 原理:每次只允许一个线程加锁后进入,执行完毕后自动解锁,其他线程才可以进来执行
public void drawMoney(double money) {
        //先搞清楚是谁来取钱
        String name = Thread.currentThread().getName();
        //1.判断余额是否够
        //this代表共享资源
        synchronized (this) {
            if(this.money >= money){
                System.out.println(name + "来取钱" + money + "成功!");
                this.money -= money;
                System.out.println(name + "取钱后,剩余余额:" + this.money);
            }else{
                System.out.println(name + "来取钱,余额不足");
            }
        }
    }

方式2:同步方法

  • 作用:把访问共享资源的核心方法给上锁
  • 原理:每次只允许一个线程加锁后进入,执行完毕后自动解锁,其他线程才可以进来执行
 public synchronized void drawMoney(double money) {

}

同步方法底层原理 

  • 如果方法是实例方法:默认用this作为锁的对象
  • 如果方法是静态方法:默认用类名.class作为锁的对象

是同步代码块好还是同步方法好?

  • 范围上:同步代码块锁的范围更小,同步方法锁的范围更大
  • 可读性:同步方法更好

方式3:Lock锁

  • Lock锁是接口,不能直接实例化,可以采用它的实现类ReentrantLock来构建Lock锁对象
 //创建了一个锁对象
    private final Lock lk = new ReentrantLock();


public void drawMoney(double money) {
        //先搞清楚是谁来取钱
        String name = Thread.currentThread().getName();
        try {
            lk.lock(); //加锁
            if(this.money >= money){
                System.out.println(name + "来取钱" + money + "成功!");
                this.money -= money;
                System.out.println(name + "取钱后,剩余余额:" + this.money);
            }else{
                System.out.println(name + "来取钱,余额不足");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lk.unlock();//解锁
        }
    }

四、线程池

什么是线程池?

  • 一个可以复用线程的技术

不使用线程池的原因

  • 创建新线程的开销是很大的,并且请求过多时,肯定会产生大量的线程出来,严重影响系统的性能

谁代表线程池?

  • 代表线程池的接口:ExEcuatorService

如何得到线程池对象?

 

  • 方式1:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象
public class ThreadPoolTest {
    public static void main(String[] args) {
//        public ThreadPoolExecutor(int corePoolSize,
//                                    int maximumPoolSize,
//                                    long keepAliveTime,
//                                    TimeUnit unit,
//                                    BlockingQueue<Runnable> workQueue,
//                                    ThreadFactory threadFactory,
//                                    RejectedExecutionHandler handler) {
        //1.创建一个线程池对象
      ExecutorService pool =   new ThreadPoolExecutor(3,5,8,
                TimeUnit.SECONDS,new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
    }
}

   //2.使用线程池处理Callable任务
        Future<String> f1 = pool.submit(new MyCallable(100));
        Future<String> f2 = pool.submit(new MyCallable(200));
        Future<String> f3 = pool.submit(new MyCallable(300));
        Future<String> f4 = pool.submit(new MyCallable(400));

        System.out.println(f1.get());
        System.out.println(f2.get());
        System.out.println(f3.get());
        System.out.println(f4.get());

 Executors工具类实现线程池

 //1-2 通过Executors创建线程池对象
      ExecutorService pool = Executors.newFixedThreadPool(3);
      //核心线程数量到底配置多少呢?
      //计算密集型的任务:核心线程数量 = CPU的核数 + 1
      //IO密集型的任务:核心线程数量 = CPU的核数 + 2

五、线程的并发、并行和生命周期

进程

  • 正在运行的程序就是一个独立的进程
  • 进程中的多个线程其实是并发并行执行的

并发的含义

  • 进程中的线程是由CPU调度执行的,但CPU能同时处理线程的数量有限,为了保证全部线程都能执行,CPU会轮询为系统的每个线程服务

并行的理解

  • 在同一个时刻,同时有多个线程在被CPU调度

线程的生命周期

  • 也就是线程从生到死的过程,经历的各种状态及状态转换

JAVA线程的状态

  • 总共定义6种状态
  • 都定义在Thread类的内部枚举类中
public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called {@code Object.wait()}
         * on an object is waiting for another thread to call
         * {@code Object.notify()} or {@code Object.notifyAll()} on
         * that object. A thread that has called {@code Thread.join()}
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }

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

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

相关文章

理解HTTP请求格式

HTTP概念 HTTP全称HyperTextTransfer Protocol(超文本传输协议)是一种用于分布式、协作式和超媒体信息系统的应用层协议&#xff1b;HTTP是一个客户端&#xff08;用户&#xff09;和服务端&#xff08;网站&#xff09;之间请求和响应的标准。 HTTP 协议是以 ASCII 码传输&…

FreeRtos-13资源管理

一、临界资源是什么 要独占式地访问临界资源,有3种方法: 1.公平竞争:比如使用互斥量,谁先获得互斥量谁就访问临界资源,这部分内容前面讲过。 谁要跟我抢,我就灭掉谁: 2.中断要跟我抢?我屏蔽中断 3.其他任务要跟我抢?我禁止调度器,不运行任务切换 二、暂停调度器…

【漏洞复现】极限OA video_file.php 任意文件读取漏洞

免责声明&#xff1a; 本文内容旨在提供有关特定漏洞或安全漏洞的信息&#xff0c;以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步&#xff0c;并非出于任何恶意目的。阅读者应该明白&#xff0c;在利用本文提到的漏洞信息或进行相关测…

线性回归模型介绍

线性回归模型是一种统计方法,用于分析两个或多个变量之间的关系。它通过拟合一条直线(称为回归线)来描述因变量(或目标变量)和一个或多个自变量(或预测变量)之间的关系。这种模型主要用于预测和解释变量间的线性关系。以下是线性回归模型的简单介绍: 1. 线性回归模型的…

文本挖掘与可视化:生成个性化词云的Python实践【7个案例】

文本挖掘与可视化&#xff1a;生成个性化词云的Python实践【7个案例】 词云&#xff08;Word Cloud&#xff09;&#xff0c;又称为文字云或标签云&#xff0c;是一种用于文本数据可视化的技术&#xff0c;通过不同大小、颜色和字体展示文本中单词的出现频率或重要性。在词云中…

技术支持与开发助手:Kompas AI的革新力量

一、引言 随着技术发展的迅猛进步&#xff0c;技术开发的高效需求日益增加。开发人员面临着更复杂的项目、更紧迫的时间表以及不断提高的质量标准。在这种背景下&#xff0c;能够提供智能支持的工具变得尤为重要。Kompas AI 正是在这种需求下应运而生的。它通过人工智能技术&a…

Arduino平台软硬件原理及使用——电位器模块的使用

文章目录 一、电位器工作原理 二、电位器与滑动变阻器的异同 三、电位器模块在Arduino中的使用 一、电位器工作原理 上图为市面上常见的电位器元件实物图&#xff0c;其结构及封装根据不同的应用场景也有着不同&#xff0c;但其原理及本质基本一致。 电位器是具有三个引出端、…

车牌号识别(低级版)

import cv2 from matplotlib import pyplot as plt import os import numpy as np from paddleocr import PaddleOCR, draw_ocr from PIL import Image, ImageDraw, ImageFont# 利用paddelOCR进行文字扫描&#xff0c;并输出结果 def text_scan(img_path):ocr PaddleOCR(use_a…

[Mysql] 数据库基本概念

前言---数据库系统发展史 当今主流数据库介绍 一、操作系统 Linux操作系统 &#xff1a;RedHat CentOS Debian Ubuntu OpenSUSE 信创标准 会让系统逐渐国产化 国产系统&#xff1a;华为 欧拉 阿里 龙蜥 腾讯 tencentOS 银河麒麟 中标麒麟…

Linux远程管理日志

实验介绍 本实验旨在实现主机将日志远程发送到堡垒机或远程服务器上&#xff0c;实现通过一台机器管理整个网络内的主机的效果。 准备两台虚拟机作为生产主机和管理机&#xff0c;保证网络通畅&#xff0c;展示如下&#xff1a; 关闭firewalld&#xff0c;通过配置rsyslog&a…

分布式锁实现方案

分布式锁 1 什么是分布式锁 ​ 就是在分布式环境下&#xff0c;保证某个公共资源只能在同一时间被多进程应用的某个进程的某一个线程访问时使用锁。 2 几个使用场景分析 一段代码同一时间只能被同一个不同进程的一个线程执行 库存超卖 (库存被减到 负数)&#xff0c;上面案…

【机器学习】【深度学习】MXnet神经网络图像风格迁移学习简介

使用部分 一、编程环境 编程环境使用Windows11上的Anaconda环境&#xff0c;Python版本为3.6. 关于Conda环境的建立和管理&#xff0c;可以参考我的博客&#xff1a;【Anaconda】【Windows编程技术】【Python】Anaconda的常用命令及实操 二、项目结构&#xff08;代码非原创…

CTF-pwn-虚拟化-【d3ctf-2021-d3dev】

文章目录 参考流程附件检查启动信息逆向分析漏洞查看设备配置信息exp 参考 https://x1ng.top/2021/11/26/qemu-pwn/ https://bbs.kanxue.com/thread-275216.htm#msg_header_h1_0 https://xz.aliyun.com/t/6562?time__1311n4%2BxnD0DRDBAi%3DGkDgiDlhjmYh2xuCllx7whD&alic…

Opencv学习项目2——pytesseract

上一次我们使用pytesseract.image_to_boxes来检测字符&#xff0c;今天我们使用pytesseract.image_to_data来检测文本并显示 实战教程 和上一次一样&#xff0c;添加opencv-python和pytesseract库 首先我们先来了解一下pytesseract.image_to_data pytesseract.image_to_data(…

无人值守工厂设备日志采集工具

免费试用下载: Gitee下载 最新版本 优势: A. 开箱即用. 解压直接运行.不需额外安装. B. 批管理设备. 设备配置均在后台管理. C. 无人值守 客户端自启动,自更新. D. 稳定安全. 架构简单,内存占用小,通过授权访问.

Exposure X7软件安装包下载 丨不限速下载丨亲测好用

根据使用者情况表明Exposure的设计鼓励您进行创造性的工作&#xff0c;使用涂刷和遮罩工具将效果有选择地应用于图片的特定区域&#xff0c;非破坏性图层使您能够混合预设和调整&#xff0c;以获得无尽的外观。我们都知道Exposure是用于创意照片编辑的最佳图片编辑器&#xff0…

【机器学习】使用Python实现图神经网络(GNN):图结构数据的分析与应用

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、引言二、图神经网络的基础知识1. 图的基本概念和术语2. 传统的图分析方法3. 图神经网络的基本原理4. GNN的基本模型 三、主要的图神经网络模型1. 图卷积网络&#xff08;Graph Convolutional Network, GCN&#xff09;2…

086. 分隔链表

题目链接 一、题目描述 (一) 题目 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。你应当保留两个分区中每个节点的初始相对位置。 (二) 示例 示例 1&#xff1a; 输入&a…

2024.6.16 机器学习周报

目录 引言 Abstract 文献阅读 1、题目 2、引言 3、创新点 4、匹配问题 5、SuperGlue架构 5.1、注意力图神经网络&#xff08;Attentional Graph Neural Network&#xff09; 5.2、最佳匹配层&#xff08;Optimal matching layer&#xff09; 5.3、损失 6、实验 6.…

数据分析第三讲:numpy的应用入门(二)

NumPy的应用&#xff08;二&#xff09; 数组对象的方法 获取描述统计信息 描述统计信息主要包括数据的集中趋势、离散程度和频数分析等&#xff0c;其中集中趋势主要看均值和中位数&#xff0c;离散程度可以看极值、方差、标准差等&#xff0c;详细的内容大家可以阅读《统计…