day17_多线程基础

今日内容

零、 复习昨日
一、作业
二、进程与线程
三、创建线程
四、线程的API

一、复习

IO流的分类

  • 方向: 输入,输出
  • 类型: 字节(XxxStream),字符(XxxReader,XxxWriter)
  • 字节输入流类名: FileInputStream
  • 字节输出流类名: FileOutputStream
  • 字符输入流类名: FileReader
  • 字符输出流类名: FileWriter

利用try-catch-finally代码写法是重点

ArrayList和LinkedList的异同点

  • ArrayList 底层是数组,容量10,装满扩容1.5倍
  • LinkedList 底层是链表
  • 相同点: 都是存储多个元素,有序,且允许重复元素
  • 不同点: 底层实现原理不一样,AL查询更新快 LL插入删除较快

解析字符串日期为日期对象的方法签名
Date date = sdf.parse(“2020-01-01”);
Date parse(String s)

解析字符串数字为int数字的方法签名
static int parseInt(String s)

int n = Integer.parseInt(“1”);


String,Date,try-catch-finally
ArrayList,HashMap
认真,慢一点,写一遍(用法,解释,代码)到本上

二、进程与线程[了解]

进程:

一个进程就是一个应用程序,进程包含线程
一个进程至少包含一个线程,大部分都是有多条线程在执行任务(多线程),每个独立运行的程序都对应一个进程。进程是资源分配的最小单位,占用独立的内存空间和系统资源

  • qq,微信,迅雷

线程:

线程是进程内部的一个执行任务

进程内多个线程是共享进程资源,线程是资源调度的最小单位(CPU调度和分派的基本单位)

  • qq在聊天,视频,传输文件
  • 迅雷同时下载多个资源

Java程序是否是多线程的吗?
答: 是! main线程,gc垃圾回收线程

为什么需要多线程?

  • 并行处理任务,提高效率

Java程序本身,是否多线程?

  • 是,至少有一个线程是"main"线程
  • 还有一个线程是没有直接看到,但是一直在"背后"运行,垃圾回收线程(GC)

三、创建线程[重点]

Thread

创建线程的方式有很多

  • 继承Thread
  • 实现Runnable接口
  • 使用Callable 和FutureTask来完成
  • 使用线程池获得线程

3.1 继承Thread

步骤

  1. 自定义类
  2. 继承Thread
  3. 重写run方法
  4. 创建子类对象
  5. 调用start方法启动线程 [特别强调,开启新线程的方法是start]
    start方法内部执行时会调用run方法执行
public class MyThread extends Thread{

    // 重写方法,方法内部,就是该线程执行的任务
    @Override
    public void run() {
        for (int i = 1; i < 101; i++) {
            System.out.println("MyThread --> "+i );
        }
    }
}
public class TestThread{
	public static void main(String[] args) {
        // 创建一个线程
        MyThread myThread = new MyThread( );
        // 启动线程,不是调用run()方法!!!!
        // 调用start方法开启新线程
        myThread.start();

        // ==============main线程执行====================
        for (int i = 1; i < 101; i++) {
            System.out.println("main     --> " + i );
        }
        
        // 自定义线程和主线程同时执行,并且出现资源争抢情况
    }
}

3.2 实现Runnable接口

步骤

  1. 自定义类
  2. 实现Runnable接口
  3. 重写run方法
  4. 创建子实现类对象
  5. 把子实现类对象当构造方法的方法参数来创建Thread对象
  6. 由thread调用start方法开启线程
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 1; i < 101; i++) {
            System.out.println("MyRunnable --> " + i);
        }
    }
}
    public static void main(String[] args) {
        // 4 创建实现类对象
        MyRunnable myRunnable = new MyRunnable( );

        // 5 把对象当构造方法参数,创建Thread对象
        Thread thread = new Thread(myRunnable);
        // 6 开启线程
        thread.start();
    }
        

匿名内部类的形式创建线程

// ============= 匿名内部类完成实现Runnable接口 ============
public class Demo4Annoy {

    public static void main(String[] args) {
        Runnable runnable = new Runnable( ) {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println("匿名内部类 --> " + i);
                }
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();

        // new Thread( new Runnable() {
        //     @Override
        //     public void run() {
        //         for (int i = 0; i < 100; i++) {
        //             System.out.println("匿名内部类 --> " + i );
        //         }
        //     }
        // }).start();

        for (int i = 0; i < 100; i++) {
            System.out.println("main --> " + i);
        }
    }
}

3.3 区别

继承Thread开启线程和实现Runnable接口开启线程有什么区别?


  • 一个继承,一个实现
  • 继承Thread后,直接创建对象即可调用start开启线程
  • 实现Runnable接口的子类,还需要再创建Thread类对象才可以调用strat开启线程

从使用便捷度来说,继承Thread开启线程会方便一点…因为创建完线程对象可以直接调用start开启线程

继承Thread类就限制了该类不能再继承别的类,因为类只能单继承,而实现接口的同时可以继承别的类,并且还允许多继承,所以推荐使用接口来实现多线程.

3.4 其他创建线程方式

package com.qf.thread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;

public class Callable01 {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		// FutureTask对象用于接收线程返回值, FutureTask 实现了RunnableFuture接口
		// public class FutureTask<V> implements RunnableFuture<V> {}
		// RunnableFuture接口继承了Runnable和Future接口,后面用到的get方法来自Future接口
		// public interface RunnableFuture<V> extends Runnable, Future<V>{}
		FutureTask<String> futureTask = new FutureTask<String>(new MyCallable());
		
		Thread thread = new Thread(futureTask);
		thread.start();

		System.out.println("-----------------");
		// 该语句阻塞程序的执行,等待线程执行完毕,获取线程返回的数据
		String result = futureTask.get();
		System.out.println(result);
	}
}

// 实现Callable接口的类
class MyCallable implements Callable<String> {
	@Override
	public String call() throws Exception {
		System.out.println(Thread.currentThread().getName());
		Thread.sleep(5000);
		return "haha";
	}
}

四、Thread的API[熟悉]

  • void start() 开启线程,会自动run方法执行线程任务
  • void run() 执行线程的方法
    • run() 方法是start开启线程后,JVM自动调用
  • void setName(String name) 给线程设置名字
    • 也可以通过构造方法,在创建线程时指定线程名
  • String getName() 获得线程的名字
  • static Thread currentThread() 返回当前正在执行的线程对象
  • join() 加入线程,等待该线程终止
  • join(int milles) 加入线程,最大等待直到毫秒数
  • void setDaemon(boolean on) 设置守护线程
  • static void sleep(long milles) 线程休眠
    • 会让当前线程暂停执行,让出系统资源,让其他线程执行
    • 时间到,当前会继续和其他争抢资源执行
  • void stop() 结束当前线程,线程死亡(已过式)
    • 被废弃的原因是因为这个中断线程太直接太暴力…

线程名字

  • String getName()
  • void setName()
  • Thread(String name)
package com.qf.thread_api;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 关于线程名字操作
 */
public class Demo1 {

    public static void main(String[] args) {

        new Thread(){
            @Override
            public void run() {
                // 给线程设置名字
                this.setName("驴车");
                // 创建线程,默认会分配名字,安装thread-x来命名
                System.out.println("开启新线程,线程名: " + getName());
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                this.setName("火车");
                // 创建线程,默认会分配名字,安装thread-x来命名
                System.out.println("开启新线程,线程名: " + getName());
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                this.setName("飞机");
                // 创建线程,默认会分配名字,安装thread-x来命名
                System.out.println("开启新线程,线程名: " + getName());
            }
        }.start();

        Thread thread = new Thread(){
            @Override
            public void run() {
            }
        };
        System.out.println(thread.getName( ));
        thread.setName("火箭");
        System.out.println(thread.getName( ));

        /**
         * 还可以通过构造方法,在创建线程时指定线程名
         */
        Thread thread5 = new Thread("子弹头"){
            @Override
            public void run() {
            }
        };
        System.out.println("线程5-->" + thread5.getName( ));
    }
}

获得当前线程对象

  • static Thread currentThread()
public static void main(String[] args) {

    new Thread("火车"){
        @Override
        public void run() {
            Thread t = Thread.currentThread( );
            System.out.println(t.getName()+",在执行..." );
        }
    }.start();

    /**
     * 获得当前正在执行的线程对象
     */
    Thread thread = Thread.currentThread( );
    System.out.println("当前正在执行的线程名字是: "+thread.getName( ));
}

线程加入

  • join()
  • join(long mill)
public static void main(String[] args) {

    Thread t1 = new Thread("线程1"){
        @Override
        public void run() {
            for (int i = 1; i < 1001; i++) {
                System.out.println(getName()+"-->"+i );
            }
        }
    };

    Thread t2 = new Thread("线程2"){
        @Override
        public void run() {
            for (int i = 1; i < 1001; i++) {
                System.out.println(getName()+"-->"+i );
                if (i == 100) {
                    try {
                        // 在当前线程下加入另一个线程
                        // 相当于"插队",直到插入的线程执行完
                        //t1.join();
                        // 让另外一个线程加入指定时间,到时后继续争抢
                        t1.join(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace( );
                    }
                }
            }
        }
    };

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

守护线程

  • void setDaemon(boolean x)

  • 守护线程是指,A线程守护B线程,即B是被保护,B是重要的,当B线程结束时A线程(守护线程)会立即结束

public static void main(String[] args) {
    Thread hs = new Thread("皇上"){
        @Override
        public void run() {
            for (int i = 1; i < 11; i++) {
                System.out.println(getName()+"工作"+i+"天" );
            }
        }
    };

    Thread fz = new Thread("妃子"){
        @Override
        public void run() {
            for (int i = 1; i < 101; i++) {
                System.out.println(getName()+"工作"+i+"天" );
            }
        }
    };

    /**
     * 不需要设置被守护,只需要设置守护线程,其他默认就是被守护线程
     * 开启线程前设置
     */
    fz.setDaemon(true);

    hs.start();
    fz.start();
}

线程休眠

  • sleep(long millis)
  • 会让当前线程陷入等待状态(阻塞)状态,让其资源让其他线程执行
public static void main(String[] args) throws InterruptedException {

    for (int i = 10; i > 0; i--) {
        System.out.println("倒计时 --> " + i );
        Thread.sleep(1000);
    }
    System.out.println("发射!" );
}

private static void show() {
    Thread t1 = new Thread("线程1"){
        @Override
        public void run() {
            for (int i = 1; i < 101; i++) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace( );
                }
                System.out.println(getName()+"-->"+i );
            }
        }
    };

    Thread t2 = new Thread("线程2"){
        @Override
        public void run() {
            for (int i = 1; i < 101; i++) {
                System.out.println(getName()+"-->"+i );
            }
        }
    };

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

结束线程

  • void stop() 结束当前线程
  • void interrupt() 设置线程中断状态为以中断
  • boolean isInterrupt() 测试返回线程是否中断
public static void main(String[] args) {
    new Thread("线程2"){
        @Override
        public void run() {
            for (int i = 1; i < 101; i++) {
                if (i == 15){
                    //this.stop(); // 直接结束线程
                    this.interrupt();// 给线程设置一个中断状态,不会真的中断线程
                    // 结束不结束取决于线程本身执行情况
                }
                System.out.println("是否中断? "+this.isInterrupted() );
                System.out.println(getName()+"-->"+i );
            }
        }
    }.start();
}

五、线程状态[面试]

线程的几种状态:

  • 创建/新建/初始
    • new 完线程对象
  • 就绪
    • 调用start
  • 等待/阻塞
    • join()或者sleep()
  • 运行
    • 执行run()方法
  • 死亡/销毁/终止
    • run方法执行完,或者调用stop()或者interrupt()中断等

清楚状态之间的转换

image-20230802165354147

image-20230302170320045

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

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

相关文章

为什么说MES管理系统是车间层与管理层的桥梁

随着制造业的快速发展&#xff0c;企业对于生产过程中的管理要求越来越高。为了满足这一需求&#xff0c;MES生产管理系统应运而生。MES管理系统作为车间层与管理层之间的桥梁&#xff0c;扮演着至关重要的角色。本文将探讨为什么说MES管理系统是车间层与管理层之间的桥梁。 一…

基础课4——客服中心管理者面临的挑战

客服管理者在当今的数字化时代也面临着许多挑战。以下是一些主要的挑战&#xff1a; 同行业竞争加剧&#xff1a;客服行业面临着来自同行业的竞争压力。为了获得竞争优势&#xff0c;企业需要不断提高自身的产品和服务质量&#xff0c;同时还需要不断降低成本、提高效率。然而…

彩虹桥架构演进之路-性能篇

一、前言 一年前的《彩虹桥架构演进之路》侧重探讨了稳定性和功能性两个方向。在过去一年中&#xff0c;尽管业务需求不断增长且流量激增了数倍&#xff0c;彩虹桥仍保持着零故障的一个状态&#xff0c;算是不错的阶段性成果。而这次的架构演进&#xff0c;主要分享一下近期针对…

【经验记录】Ubuntu系统安装xxxxx.tar.gz报错ImportError: No module named setuptools

最近在Anaconda环境下需要离线状态&#xff08;不能联网的情况&#xff09;下安装一个xxxxx.tar.gz格式的包&#xff0c;将对应格式的包解压后&#xff0c;按照如下命令进行安装 sudo python setup.py build # 编译 sudo python setup.py install # 安装总是报错如下信息&am…

竞赛 题目:基于大数据的用户画像分析系统 数据分析 开题

文章目录 1 前言2 用户画像分析概述2.1 用户画像构建的相关技术2.2 标签体系2.3 标签优先级 3 实站 - 百货商场用户画像描述与价值分析3.1 数据格式3.2 数据预处理3.3 会员年龄构成3.4 订单占比 消费画像3.5 季度偏好画像3.6 会员用户画像与特征3.6.1 构建会员用户业务特征标签…

数字化时代,VR虚拟展厅为企业带来全新商机

临近年关&#xff0c;各个行业都想在年关将至之时冲一波销量&#xff0c;各种婚博会、家博会、车展会多不胜数。但是线下展会终归是场地有限&#xff0c;因此为了扩大受众范围&#xff0c;同时节约一定宣传成本&#xff0c;实现全球范围的展示和推广&#xff0c;不少企业都会选…

【机器学习7】优化算法

1 有监督学习的损失函数 1.1 分类问题 对二分类问题&#xff0c; Y{1,−1}&#xff0c; 我们希望sign f(xi,θ)yi&#xff0c; 最自然的损失函数是0-1损失&#xff0c; 函数定义特点0-1损失函数非凸、非光滑&#xff0c;很难直接对该函数进行优化Hinge损失函数当fy≥1时&…

PG数据库实现merge into方法

语法格式1&#xff1a;有则更新&#xff0c;无则插入 insert into table_1(column_1,column_2, column_3) select column_1,column_2,column_3,from table_2on conflict (column_1)do update setcolumn_2 excluded.column_2,column_3 excluded.column_3如&#xff1a; inse…

墨西哥专线一次最多发几条柜?

墨西哥专线一次最多发几条柜这个问题涉及到海运业务中的一些复杂因素。墨西哥是一个重要的贸易国家&#xff0c;其与美国和加拿大之间的贸易往来非常频繁&#xff0c;因此海运业务也非常活跃。在墨西哥专线上&#xff0c;一次最多发几条柜通常取决于以下几个因素&#xff1a; 1…

使用X2Keyarch迁移CentOS至浪潮信息KeyarchOS体验

浪潮信息KeyarchOS简介 浪潮信息研发的云峦操作系统KeyarchOS(简称KOS), 是一款面向政企、金融等企业级用户的 Linux 服务器操作系统&#xff0c;其稳定性、安全性、兼容性和性能等核心能力均已得到充分验证。历经近10年自主研发历史&#xff0c;支持x86、ARM、Power主流架构处…

智慧工地综合管理平台-项目开发管理规范

目的 本规范制定旨在规范项目的开发流程,提高软件开发质量和效率,降低开发成本和风险。该规范包括但不限于以下几个方面: 项目管理 包括项目计划、需求分析、设计、开发、测试、发布等环节,以及项目进度、质量和风险管理等方面项目计划管理:制定项目计划,包括确定项目目…

二百零二、Hive——Hive解析JSON字段(单个字段与json数组)

一、目的 用Flume采集Kafka写入到Hive的ODS层在HDFS路径下的JSON数据&#xff0c;需要在DWD层进行解析并清洗 &#xff08;一&#xff09;Hive的ODS层建静态分区外部表 create external table if not exists ods_queue(queue_json string ) comment 静态排队数据表——静…

搭建成功simulink-stm32硬件在环开发环境

本次实验所使用的软件版本和硬件平台参数如下&#xff1a; Matlab版本: 2021b STM32硬件平台&#xff1a;YF_STM32_Alpha 1R4(参考自STM32 Nucleo F103RB官方开发板) YF_STM32_Alpha开发板 STM32 Nucleo F103RB 开发板 2.1 STM32硬件支持包下载 读者朋友平时使用的是和谐版M…

夯实c语言基础

题干以下关于函数的叙述中正确的是&#xff08;  d &#xff09;。   A.函数调用必须传递实参   B.函数必须要有形參   C.函数必须要有返回值   D.函数形参的类型与返回值的类型无关 题干以下程序实现&#xff0c;打印任意奇数行菱形星塔&#xff0c;请填空。 void…

dll文件【C#】

加载方法&#xff1a; [DllImport("controlcan.dll")] public static extern UInt32 VCI_OpenDevice(UInt32 DeviceType, UInt32 DeviceInd, UInt32 Reserved); 文件存放位置&#xff1a; 一般放Debug文件夹下。 运行错误&#xff1a; 原因是CPU位数选择不对&…

Wireshark抓包工具配置以及MQTT抓包分析

1、Wireshark抓包工具使用 打开Wireshark选择&#xff0c;需要抓取的物理网卡&#xff0c;添加过滤设置。 单击“捕获”&#xff0c;选择选项&#xff0c;输入需要捕获的IP地址和端口号。 如&#xff1a; ip host 10.60.4.45 and tcp port 1883 ip host 10.60.4.45 and http p…

【Mycat2实战】三、Mycat实现读写分离

1. 无聊的理论知识 什么是读写分离 读写分离&#xff0c;基本的原理是让主数据库处理事务性增、改、删操作&#xff0c; 而从数据库处理查询操作。 为什么使用读写分离 从集中到分布&#xff0c;最基本的一个需求不是数据存储的瓶颈&#xff0c;而是在于计算的瓶颈&#xff…

从CentOS向KeyarchOS操作系统的wordpress应用迁移实战

文章目录 从CentOS向KeyarchOS操作系统的wordpress应用迁移实战一、使用浪潮信息X2Keyarch迁移工具完成操作系统的迁移1.1 迁移前的验证1.2 执行迁移评估1.3 开始迁移1.4 验证迁移结果1.5 迁移后的验证 二、总结 从CentOS向KeyarchOS操作系统的wordpress应用迁移实战 CentOS是一…

顶点着色器

顶点着色器(vertex shader)是-一段运行在图形卡GPU中的程序&#xff0c;它可取代固定功能流水线中的变换和光照环节(当然&#xff0c;这也不是绝对的&#xff0c;因为在硬件不支持顶点着色器的情况下&#xff0c;Dict3D运行时就会用软件运算方式来模拟顶点着色器) 可以看出&…

day22_mysql

今日内容 零、 复习昨日 一、MySQL 一、约束 1.1 约束 是什么? 约束,即限制,就是通过设置约束,可以限制对数据表数据的插入,删除,更新 怎么做? 约束设置的语法,大部分是 create table 表名( 字段 数据类型(长度) 约束, 字段 数据类型(长度) 约束 );1.1 数据类型 其实数据类型…