day17_多线程基础

news2024/11/26 20:45:59

今日内容

零、 复习昨日
一、作业
二、进程与线程
三、创建线程
四、线程的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

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

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

相关文章

Spring lOC的注解使用与开发

Spring Spring IoC注解式开发为什么使用注解Spring注解的使用Value注解Autowired注解全注解式开发 Spring IoC注解式开发 为什么使用注解 注解的存在主要是为了简化XML的配置&#xff0c;注解的开发能大大提高我们的开发效率的&#xff0c;但它在一定程度上违背了OCP原则。 …

智能客服外包与传统呼叫中心人力外包对比有哪些优势?

随着人工智能技术的飞速发展&#xff0c;智能客服外包服务为企业提供了更高效、更智能的客户服务解决方案&#xff0c;越来越多的企业更愿意选择智能客服外包服务。与传统呼叫中心人力外包相比&#xff0c;智能客服外包有哪些优势呢&#xff1f; 减轻人力资源压力 智能客服系统…

Linux指令(二)

&#x1f3a0;&#x1f3a0;&#x1f3a0;&#x1f3a0;&#x1f3a0;&#x1f3a0;&#x1f3a0;&#x1f3a0;&#x1f3a0;&#x1f3a0;&#x1f3a0;&#x1f3a0;&#x1f3a0;&#x1f3a0;&#x1f3a0;&#x1f3a0; &#x1f396;️&#x1f396;️&#x1f396;️&a…

设备报修流程要怎么优化?工单管理系统如何提高设备维修效率?

在当今快速发展的数字化时代&#xff0c;传统的设备报修流程已经难以满足企业的需求。纸质记录、电话通知等传统方式不仅效率低下&#xff0c;而且容易造成信息遗漏和错误。为了解决这些问题&#xff0c;企业需要引入一种更加高效、便捷的维修管理系统——的修工单管理系统。  …

TSINGSEE青犀视频平台EasyCVR修改设备通道不生效是什么原因?该如何解决?

视频监控TSINGSEE青犀视频平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;TSINGSEE青犀视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多路视频流&#…

如何在Windows 10上恢复丢失的文件?

丢失文件时该怎么办&#xff1f; 在使用电脑的过程中&#xff0c;我们经常会遇到丢失重要文件的情况。无论是意外删除、病毒攻击还是电脑格式化&#xff0c;都可能导致文件丢失。在面对这些情况时&#xff0c;大多数人总是会问&#xff1a;“如何在电脑上恢复丢失的文件&am…

每天学习一点点之从 SonarQube Bug 看对线程中断异常的处理

最近在基于 SonarQube 对代码进行质量优化&#xff0c;说实话&#xff0c;之前觉得 SonarQube 这种很无聊&#xff0c;但最近静下心来看了一些扫描出来的问题后&#xff0c;发现这种工具作用还是挺大的&#xff0c;能够帮助我们找到代码中的隐藏缺陷&#xff0c;从而夯实基础。…

遍历一个对象,并得出所对应的值

var dates {//定义的对象year:now.getFullYear(),month:now.getMonth()1,date:now.getDate(),hour:now.getHours(),minute:now.getMinutes(),second:now.getSeconds() }//开始遍历循环 var val; for (val in dates){console.log(对象名称&#xff1a;val-对象的值&#xff1a;…

【性能】如何计算 Web 页面的 FP 指标

什么是 FP 指标 FP (First Paint) 为首次渲染的时间点&#xff0c;在性能统计指标中&#xff0c;从用户开始访问 Web 页面的时间点到 FP 的时间点这段时间可以被视为 白屏时间&#xff0c;也就是说在用户访问 Web 网页的过程中&#xff0c;FP 时间点之前&#xff0c;用户看到的…

网络嵌入综述

图嵌入综述整理&#xff08;上&#xff09; 来源&#xff1a;图算法探索系列&#xff08;一&#xff09;&#xff1a;图嵌入模型的原理和应用篇【万字长文】 图9是DeepWalk模型在推荐场景下的应用。图9&#xff08;a&#xff09;显示的是不同用户在不同Session中的item点击序列…

8年经验的软件工程师建议

我希望在职业生涯早期就开始做的事情和我希望以不同的方式做的事情。 大家好&#xff0c;我已经做了八年半的软件工程师。这篇文章来源于我最近对自己在职业生涯中希望早点开始做的事情以及希望以不同方式做的事情的自我反思。 我在这里分享的对任何希望提高和进步到高级甚至…

【PyQt小知识 - 2】:QTextEdit内容的更新和获取、隐藏或显示滚动条、光标插入文本、文本自适应移动

文章目录 QTextEdit更新和获取内容隐藏或显示滚动条光标插入文本文本自适应移动 QTextEdit 更新和获取内容 更新&#xff1a;QTextEdit().setText(text) 或 QTextEdit().setPlainText(text) 获取&#xff1a;QTextEdit().toPlainText() setText()和setPlainText()的区别&…

自动化测试Mock神器:轻松模拟HTTP请求..

一、背景 在日常测试过程中或者研发开发过程中&#xff0c;目前接口暂时没有开发完成&#xff0c;测试人员又要提前介入接口测试中&#xff0c;测试人员不仅仅只是简单的编写测试用例&#xff0c;也可以通过一些mock的方法进行来提前根据接口测试的情况进行模拟返回接口的信息…

怎么选好用的电脑监控软件

在选择好用的电脑监控软件时&#xff0c;需要考虑多个因素&#xff0c;包括功能和特性、安全性和隐私保护、用户界面、实时监控和报警功能、日志记录和报告功能、兼容性以及用户评价和口碑等。 首先&#xff0c;需要明确你需要监控的内容&#xff0c;例如屏幕活动、应用程序使用…

U盘变成了.lnk,怎么处理

没曾想客户电脑是是不是有个病毒啥的&#xff0c;把我的U盘直接干成了只有一个.lnk的一个快捷方式&#xff0c;后面百度找了很多方法&#xff0c;最后找到了一个非常实用的方法&#xff0c;后整理了一下交给大家 方法如下&#xff1a; 1.找到电脑U盘文件 2.搜索框中输入你之…

正则提取记录

使用正则 https?:\/\/([^\/\s])/

TikTok女性创作者:媒体世界的新领袖

在数字时代&#xff0c;社交媒体已成为媒体和娱乐产业的关键组成部分&#xff0c;而TikTok作为最受欢迎的短视频分享平台之一&#xff0c;为女性创作者提供了一个独特的机会来在媒体世界中崭露头角。 这个平台不仅为女性创作者提供了一个创作和分享自己的声音、观点和创意的空…

Arthas搭建与使用

背景 在平时开发过程中经常会遇到日志打印有问题、代码不知道是否执行、定位运行缓慢的代码段等需求&#xff0c;这时往往需要排查很久&#xff0c;并且由于我们基于docker进行部署&#xff0c;一旦有问题要发包调试的话构建过程还是比较复杂耗时的&#xff0c;有时候打包只是…

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

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

动画短片怎么制作gif?一个方法简单又好用

网络上常常能看到动画短片&#xff0c;虽然时长短但是内容很丰富。当我们想要将这种动画短片做成gif格式图片的时候&#xff0c;应该怎么办呢&#xff1f;很简单&#xff0c;通过使用在线制作动画&#xff08;https://www.gif.cn/&#xff09;网站&#xff0c;无需下载软件上传…