【JavaEE】认识线程Thread类及常用方法线程状态

news2024/11/14 14:47:12

目录

一:认识线程:

二、线程的优点:

三、进程和线程的区别(面试题): 

四、第一个多线程程序: 

五、创建线程的方式:

六、Thread类及常用方法

Thread类常见构造方法: 

Thread(String name)

Thread(Runnable target,String name)

Thread常见属性: 

ID&名称: 

状态: 

优先级 

后台线程 

存活 

中断 


一:认识线程:

每一个线程就是一个“执行流”。每个线程之间都可以按照顺序执行自己的代码,多个线程之间可以同时执行自己的代码。比如我们之前一直写的程序都只是在main线程中写的代码,以前写的代码都是单个线程的。

那么为什么会出现线程?主要有2个原因:

1)并发编程的需要 

单核CPU的发展已经到了瓶颈,现在已经到了多核CPU的时代,而并发编程可以让CPU的资源得到充分的利用。

2)进程太“重”了。

虽然进程也可以实现并发编程,但是进程还是太“重”了。

进程在创建时开销非常大

进程在销毁是开销非常大

进程在调度的时候也开销非常大!

我们这里所说的“重”指的是“资源分配/回收”。

二、线程的优点:

所以我们的线程就应运而生。相对于进程而言。线程就更加的“轻量化”了,所以线程也被称为“轻量化进程”。这里说的轻量是因为线程在创建、销毁和调度的时候的开销都要比进程低。而线程之所以开销低的原因又在于线程省去了一些“申请资源和释放资源的步骤”。

比如这样的一个例子:

小明家开了一个工厂来生产冰箱,经过了一段时间的经营,发现生产的冰箱非常的受欢迎,销量很高,于是小明想到了两种方案来提高生产力:

方案一(多进程方案):再寻找一个工业场地,购进一批同样的机器来进行生产。

方案二(多线程方案):把原工厂的地方拾掇拾掇,腾出一块地方,购进一批新的机器放机器进行生产

 显然我们可以看出,第二种方案(多线程)的开销要明显低于第一种方案(多进程)。因为第二种方案没有进行更大的资源开销,而是在原工厂的基础上进行了复用,也就是还是利用了原场地。这样下来的开销就大大减少了。

三、进程和线程的区别(面试题): 

1.、进程包含线程。一个进程中可以有一个线程,也可以有多个线程。

2、进程和线程都可以解决并发编程问题,但是进程在频繁的创建和销毁的时候开销更大,线程更小。(线程比进程更加的轻量)

3、进程是操作系统资源分配的基本单位,线程是操作系统进行调度的基本单位。

4、进程与进程之间不共享内存空间,同一个进程中的线程共享内存空间。(这就可能会出现一个线程崩了,别的也会收到影响,而进程之间不会影响。也就是说进程比线程更安全)

四、第一个多线程程序: 

线程是操作系统里面的概念,Java标准库中的Thread类可以视为是对操作系统提供的API进行了抽象和封装。

通过第一个多线程的程序感受一下多线程和单一线程的区别。

package Thread;

class myThread extends Thread{
    //使用一个boolean类型进行判断,让该线程只打印100次
    private boolean flag=true;
    private int count=1;
    @Override
    public void run() {

        while(flag){
            if(count==100){
                flag=false;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("hello Thread");
            count++;
        }

    }
}
public class ThreadDemo2 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new myThread();
        t.start();
        //主线程打印50次
        for (int i = 0; i <50 ; i++) {
            Thread.sleep(500);
            System.out.println("hello main");
        }


    }
}

 

该程序并没有先执行其中一个线程,在执行另一个的线程,这就是多线程的魅力所在。  

我们从上述结果中也可以看到一个现象就是main线程和t线程谁先执行是不确定的,是完全由我们的系统自己决定的。所以线程的调度是“抢占式执行,随机调度”。 

五、创建线程的方式:

我们创建线程可以有五种方式:

1、创建子类继承Thread类,重写run方法。

package Thread;

class myThread1 extends Thread{
    @Override
    public void run() {
        System.out.println("hello Thread");
    }
}
public class ThreadDemo3 {
    public static void main(String[] args) {
        Thread t1=new myThread1();
        t1.start();
    }
}

run方法描述了该线程要执行的任务内容,即要执行的代码,而调用start方法才是真正创建了线程,才会执行任务。 

2、实现Runnable接口,重写run方法。

package Thread;

class myRunnable implements Runnable{

    @Override
    public void run() {
        System.out.println("hello Thread");
    }
}
public class ThreadDemo4 {
    public static void main(String[] args) {
        myRunnable runnable=new myRunnable();
        Thread t=new Thread(runnable);
        t.start();

    }
}

 

这个方法是通过实现Runnable接口,创建出一个Runnable的实例,把这个实例传给Thread对象,通过这个实例来描述要执行的任务。 

3、匿名内部类创建Thread子类对象。

package Thread;

public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread t=new Thread(){
            @Override
            public void run() {
                System.out.println("hello Thread");
            }
        };

        t.start();

    }
}

4、匿名内部类创建Runnable子类对象

package Thread;

public class ThreadDemo6 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello Thread");
            }
        });
        t.start();
    }
}

 

5、使用lambda表达式(最推荐写法)

package Thread;

public class ThreadDemo7 {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            System.out.println("hello Thread");
        });
        t.start();
    }
}

六、Thread类及常用方法

Thread类常见构造方法: 

Thread(String name)

这个方法就是在我们创建线程的时候,对线程进行命名。我们上面的t线程这样的说法注意这里的t是指Thread对象,不是我们线程的名字。所以我们可以通过这个方法对线程进行命名,避免线程混乱的情况。

package Thread;

public class ThreadDemo8 {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            while (true) {
                System.out.println("hello Thread10086");
            }
        },"Thread10086");
        
        t.start();
    }
}

然后我们运行后可以通过java的jdk自带的工具程序来进行线程的管理和监视。这就用到了我们的jconsole工具。

 然后就是介绍一下Thread(Runnable target,String name)

Thread(Runnable target,String name)

 这个就是上述的使用Runnable对象来创建线程的方法了。

package Thread;

public class ThreadDemo9 {
    public static void main(String[] args) {
        Thread t=new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    System.out.println("hello Thread10010");
                }

            }
        },"Thread10010");
        t.start();
    }
}

然后我们通过jconsole观察一下:

然后下面是Thread的几个常用的属性。 

Thread常见属性: 

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()

ID&名称: 

id是每个线程独一无二的身份标识。

名称是每个线程的名字。

package Thread;

public class ThreadDemo10 {
    public static void main(String[] args) {
        Thread t1=new Thread(()->{

        },"T1");
        Thread t2=new Thread(()->{

        },"T2");

        t1.start();
        t2.start();
        System.out.println(t1.getId());
        System.out.println(t2.getId());
        System.out.println(t1.getName());
        System.out.println(t2.getName());
    }
}

状态: 

状态是当前线程所处的状态。

线程的状态有以下几种:

1、NEW   安排了工作,还没有开始行动

2、RUNNABLE     可工作的(包括正在工作和即将开始工作)

3 、TERMINATED    工作完成了

4、BLOCKED        排队等待其他事情

5、WAITING        排队等待其他事情

6、TIMED_WAITING        排队等待其他事情

NEW

首先说一下NEW,这个就是在我们的run方法中没有进行任务的执行。

package Thread;

public class ThreadDemo11 {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            System.out.println("hello");
        });
       // t.start();
        System.out.println(t.getState());
    }
}

  

 我们没有进行线程的启动,就说明了我们只是描述了任务是什么(打印hello),但是没有去执行这个任务,所以状态就是NEW

RUNNABLE

那么我们如果的任务没有进行描述,但是我们启动了线程,就相当于老板没有给员工下达任务,员工此时就是可以执行任务的状态RUNNABLE(就是闲着)。

package Thread;

public class ThreadDemo12 {
    public static void main(String[] args) {
        Thread t=new Thread(()->{

        });
        t.start();
        System.out.println(t.getState());
    }
}

TERMINATED 

这个就是表示线程执行完毕了。我们可以用以下代码做理解。

package Thread;

public class ThreadDemo12 {
    public static void main(String[] args)   {
        Thread t=new Thread(()->{

        });
        t.start();
        //使用一个sleep使得t线程先执行完毕
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(t.getState());

        }
}

BLOCKED 

BLOCKED这个状态常见于加锁状态,当我们对其进行加锁(synchronized)之后 ,别的对象来获取锁的时候就需要阻塞等待,直到加锁的对象释放锁之后,才有机会获取到锁。

目前先知道对一个代码块加锁后就会出现所谓的加锁状态即可,后面会告诉大家为什么我们要进行加锁操作。 

WAITING 

WAITING表示排队等待其他事情。(这里先不展开,后面会介绍)

TIMED_WAITING

TIMED_WAITING也表示排队等待其他事情,但是这里的排队是由于系统调用了sleep方法而进入的状态。表示了当前线程需要阻塞等待一定的时间。

package Thread;

public class ThreadDemo14 {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            while (true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            
        });
        t.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(t.getState());
    }
}

附赠状态一览表(简略示意)

 

 

优先级 

优先级高的线程理论上来说更容易被调度到 

后台线程 

关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行

存活 

是否存活,即简单的理解,为 run 方法是否运行结束了

中断 

有关线程中断的问题我们后面再总结,这点的篇幅可能会有点长,不便于总结在此处。 

 好了,今天的认识线程&Thread类及常用方法&线程状态就大概总结到这里了,下一篇准备总结一下有关线程安全的那些事。

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

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

相关文章

整理介绍字符函数和字符串函数+内存函数

本篇重点介绍处理字符和字符串的库函数的使用和注意事项 本篇重点本篇重点介绍处理字符和字符串的库函数的使用和注意事项前言&#xff1a;求字符串长度strlen拷贝字符串函数strcpy&#xff08;追加&#xff09;连接字符串函数strcat比较两个字符串函数strcmp对上面改进字符串函…

Mac应用程序无法打开或文件损坏的处理方法

很多用户在安装 盗版 Mac软件的时候&#xff0c;经常会遇到提示“xxx.app已损坏&#xff0c;打不开。您应该将它移到废纸篓“或”打不开的xxx.app&#xff0c;因为它来自身份不明的开发者”&#xff0c;等多种打不开盗版软件的各种提示&#xff0c;正版软件则不会出现。 错误截…

17种编程语言实现排序算法-基数排序

开源地址 https://gitee.com/lblbc/simple-works/tree/master/sort/ 覆盖语言&#xff1a;C、C、C#、Java、Kotlin、Dart、Go、JavaScript(JS)、TypeScript(TS)、ArkTS、swift、PHP。 覆盖平台&#xff1a;安卓(Java、Kotlin)、iOS(SwiftUI)、Flutter(Dart)、Window桌面(C#)、…

事件冒泡和时间捕获

事件冒泡和事件捕获 最近&#xff0c;在复习Vue的时候&#xff0c;发现自己对于事件冒泡和事件捕获的理解存在一定的错误。于是想写一份笔记来总结一下事件冒泡和事件捕获。✌✌✌ 一、事件 1、事件的三个阶段&#xff1a;事件捕获->事件目标->事件冒泡 捕获阶段&am…

MySQL 性能优化浅析及线上案例

作者&#xff1a;京东健康 孟飞 1、 数据库性能优化的意义 业务发展初期&#xff0c;数据库中量一般都不高&#xff0c;也不太容易出一些性能问题或者出的问题也不大&#xff0c;但是当数据库的量级达到一定规模之后&#xff0c;如果缺失有效的预警、监控、处理等手段则会对用户…

设计模式学习(十二):Decorator装饰器模式

一、什么是Decorator模式假如现在有一块蛋糕&#xff0c;如果只涂上奶油&#xff0c;其他什么都不加&#xff0c;就是奶油蛋糕。如果加上草莓&#xff0c;就是草莓奶油蛋糕。如果再加上一块黑色巧克力板&#xff0c;上面用白色巧克力写上姓名&#xff0c;然后插上代表年龄的蜡烛…

JavaEE5-Spring更简单的读取和存储对象

目录 1.存储Bean对象 1.1.前置工作&#xff1a;在配置文件中设置bean扫描的根路径&#xff08;重要&#xff09; 1.2.添加注解存储Bean对象到Spring中 1.2.1.类注解(添加到某个类上&#xff0c;将当前的类存储到Spring中)&#xff1a;Controller&#xff0c;Service&#x…

树,堆,二叉树的认识

1.树概念及结构 1.1树的概念 注意&#xff1a;树形结构中&#xff0c;子树之间不能有交集&#xff0c;否则就不是树形结构 1.2 树的相关概念 1.3 树的表示 树结构相对线性表就比较复杂了&#xff0c;要存储表示起来就比较麻烦了&#xff0c;既然保存值域&#xff0c;也要保存…

Gateway服务网关

Gateway服务网关一、网关介绍二、gateway快速入门1.创建gateway服务&#xff0c;引入依赖2.编写启动类3.编写基础配置和路由规则4.重启测试5.网关路由的流程图三、断言工厂四、过滤器工厂1.路由过滤器的种类2.请求头过滤器3.默认过滤器4.总结五、全局过滤器1.全局过滤器作用2.自…

fpga实操训练(系统开发和硬件接口)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 相信很多学习fpga的同学都会有这样的一个感受,一开始fpga学习还比较简单,但是一旦涉及到呼吸灯、uart、spi、iic、ddr2后面就会越来越难。遇到这样的困难之后,学习的激情一下子少…

从零搭建一个组件库(一)项目环境搭建

文章目录前言monorepo架构1.monorepo架构的优势2.使用pnpm搭建monorepo架构&#xff08;1&#xff09;全局安装pnpm&#xff08;2&#xff09;初始化项目&#xff08;3&#xff09;新建workspace.yaml文件4.不同包之间的相互引用TypeScript支持1.安装TypeScript2.初始化TypeScr…

http三次握手四次挥手详解

1、 TCP的三次握手和四次挥手实质就是TCP通信的连接和断开。 三次握手&#xff1a;为了对每次发送的数据量进行跟踪与协商&#xff0c;确保数据段的发送和接收同步&#xff0c;根据所接收到的数据量而确认数据发送、接收完毕后何时撤消联系&#xff0c;并建立虚连接。 四次挥…

C++6:STL-模拟实现string

string时STL中的模板库之一&#xff0c;类似于专门处理字符串的数据结构&#xff0c;在模拟实现并探讨其中构造的巧妙之处之前&#xff0c;我们短浅的认识一下STL是什么 目录 什么是STL STL的诞生 关于string string的模拟实现 构造函数和析构函数 实现简单的string打印 …

【蓝桥杯】简单数论2——快速幂矩阵快速幂

1、快速幂 1.1运算模 定义&#xff1a;模运算为a除以m的余数&#xff0c;记为a mod m&#xff0c;有a mod m a % m。 模运算是大数运算中的常用操作&#xff1a;如果一个数太大&#xff0c;无法直接输出&#xff0c;或者不需要直接输出&#xff0c;可以把它取模后&#xff0…

Android 深入系统完全讲解(37)

7.5 源码讲解 dlopen 打开动态库 dlsym 找到符号 (*print_func)(); 调用方法 我们可以看到&#xff0c;要使用一个 so 库的某个方法&#xff0c;就上面三步骤&#xff0c;加载 &#xff0c;查找 &#xff0c;使用 。我 们这里调用了 so 库中的 my_print 方法。 7.6 运行 我们把…

Linux——进程间通信

文章目录前言1. 进程间通信方式的一些标准&#xff1a;2. 管道2.1 什么是管道2.2 管道的原理2.3 匿名管道2.3.1 实例代码1. demo代码2. 总结管道的特点&#xff0c;理解以前的管道 |3. 扩展——进程池2.4 管道读写规则2.5 命名管道2.5.1 创建一个命名管道2.5.2 命名管道的打开规…

Python break用法详解

我们知道&#xff0c;在执行 while 循环或者 for 循环时&#xff0c;只要循环条件满足&#xff0c;程序将会一直执行循环体&#xff0c;不停地转圈。但在某些场景&#xff0c;我们可能希望在循环结束前就强制结束循环&#xff0c;Python 提供了 2 种强制离开当前循环体的办法&a…

路由处理及功能(实现了权限控制vue admin)

界面简化 将 template 改为&#xff1a; <template><div class"login-container"><el-formref"loginForm":model"loginForm":rules"loginRules"class"login-form"autocomplete"on"label-positio…

Mybatis遇到的脑残问题

一、MySQL的版本问题 有的教程mysql是8.0版本使用jar包不一样 <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0</version></dependency>然后我查了一下我的mysql版本是5.7版…

分支语句与循环语句

文章目录 什么是语句&#xff1f; 分支语句&#xff08;选择结构&#xff09;循环语句goto语句前言 一、什么是语句&#xff1f; C语句可分为以下五类&#xff1a; 1. 表达式语句 2. 函数调用语句 3. 控制语句 4. 复合语句 5. 空语句 控制语句用于控制程序的执行流程&#xff0…