Java线程入门

news2024/11/19 23:15:01

目录

一.线程相关概念

1.程序(program)

2.进程

3.线程

4.其他相关概念

二.线程的创建

1.继承Thread

2.Runnable接口

3.多线程机制(重要)

4.start()

三.线程终止--通知

四.线程(Thread)方法

1.常用方法

2.yield和join

3.setDaemon

五.线程的生命周期

六.Synchronized 

1.线程同步机制

2.实现方法

2.1 同步代码块

2.2 同步方法

3.互斥锁

4.释放锁


一.线程相关概念

1.程序(program)

为了完成特定的任务,用某种语言编写的一组指令的集合。简单点说就是我们写的代码。

2.进程

进程是程序的一次执行过程,或是正在运行的一个程序。它是一个动态过程:产生 -> 存在 -> 消亡。

3.线程

由进程创建,是进程的一个实体,一个进程里有多个线程,线程也可以有子线程。

单线程:同一个时刻,只允许执行一个线程

多线程:同一个时刻,可以执行多个线程

4.其他相关概念

并发:同一时刻,多个任务交替执行,简单来说就是单核CPU实现多个任务。这里注意,单核CPU,一次就能进行一个任务,比如我们切换应用,看起来是都两个应用都在运行,实则是CPU的切换速度很快,快速切换完成的,不是在同时进行多个任务。

并行:同一个时刻,多个任务同时执行。多核CPU可以实现并行。这个跟上面的例子相对,每一个应用都有一个CPU工作。

二.线程的创建

1.继承Thread

我们可以通过继承Thread(线程)来创建线程。

当一个类继承了 Thread 类,该类就可以当线程使用。我们会重写run()方法,写上自己的业务代码。Thread 类 实现了 Runnable 接口的run方法

比如这里有一个Cat类:

class Cat extends Thread{
    public void run(){
    //重写run方法,实现我们需要的业务逻辑
        int time=1;
        while(true){
            System.out.println("time = "+time);
            try {
                //睡眠1s
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(time==8){
                break;
            }
            time++;
        }
    }
}

现在Cat类可以当作线程使用,我们在main方法中使用了这个线程:
 

public static void main(String[] args) {
    //创建一个cat对象
    Cat cat=new Cat();
    cat.start();

2.Runnable接口

我们知道,Java一个类只能继承一个父类,如果我们要继承Thread的类已经继承了一个父类,那么怎么才能实现?

使用Runnable接口,使用这个接口后,实现run方法即可(前面说了Thread类的run方法是实现Runnable中的run方法)。

这里举一个Dog的例子,假设我们的Dog已经继承了Animal类了:

class Dog extends Animal implements Runnable{
    int count=0;
    @Override
    public void run() { //普通方法
        while(true){
            System.out.println("count = "+count);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count++;
        }
    }
}

在main方法中的使用方法也不一样了:

Dog dog=new Dog();
//dog.start(); 这里不能调用start
Thread thread = new Thread(dog);
thread.start();

3.多线程机制(重要)

现在我们运行下面的代码:

public class Thread01 {
    public static void main(String[] args) throws InterruptedException {
        //创建一个cat对象
        Cat cat=new Cat();
        cat.start();

        for (int i = 1; i <= 8; i++) {
            Thread.sleep(1000);
            System.out.println("i = "+i);
        }
    }
}
class Cat extends Thread{
    public void run(){
        int time=1;
        while(true){
            System.out.println("time = "+time);
            try {
                //睡眠1s
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(time==8){
                break;
            }
            time++;
        }
    }
}

查看输出的内容,我们发现输出的内容是交替出现的,这里就说明了一个事实:主线程与子线程交替执行。

当一个main线程启动一个子线程Thread-0,主线程不会阻塞,会继续执行。这也就是为什么我们可以看到其交替出现的原因。

当我们执行程序的时候(开了一个进程)先会开一个main线程,随后开一个子线程Thread-0,main线程结束后,子线程还会进行进行,直到结束为止。

总而言之,一个main线程结束,不代表整个进程都会结束,当全部线程结束的时候,进程才会结束。

4.start()

有人可能会发现,如果我们调用run()方法,一样可以打印,为什么要用start()而不用run()呢?

因为我们写的run() 方法,它只是一个普通的方法。我们调用start()方法,其底层会调用start0()方法,这个方法才是关键。真正实现多线程的效果是start0()

start0()是本地方法,是JVM调用的。

三.线程终止--通知

顾名思义,通知线程,让其关闭。当然,程序听不懂我们说的,但我们可以给它传一个值告诉它:停下吧。这里我们传入了一个布尔变量,让其控制线程的结束:

class T extends Thread{
    public boolean loop=true;
    public void run(){
        while(loop){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("T 在运行");
        }
    }

    public void setLoop(boolean b) {
        loop=b;
    }
}

四.线程(Thread)方法

1.常用方法

方法说明
setName设置线程名称

getName

返回线程名称
start是该线程开始执行,JVM调用该线程的start0()方法
run调用线程对象 run 方法
setPriority更改线程的优先级
getPriority获取线程的优先级
sleep在指定的毫秒内让当前正在执行的线程休眠(暂停执行)
interrupt中断线程,注意不是结束

2.yield和join

方法说明
yield线程礼让,即让出CPU,让其它线程执行,但礼让的时间不确定,所以不一定礼让成功
join线程插队,线程插队一旦插队成功,肯定会先执行完插入的线程的所有任务

比如一开始线程A,B都在执行,想让A先暂停,让B先执行完。如果用yield方法,不一定能让A暂停,这取决于CPU资源占用量。但如果使用join,直接插队,B先把线程全部执行完,A就在那暂停。

3.setDaemon

方法说明
setDaemon设置为true,就是开启守护线程

用户线程(工程线程):当线程的任务全部执行完或通知方式结束

守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束。常见守护线程:垃圾回收机制。

五.线程的生命周期

线程一共有六种状态,这里特别说明一下Runnable状态。

当进入到Runnable状态时,不是马上就开始运行了,是先变成Ready,被调度器选中才执行。

整个过程看图就可以理解。

六.Synchronized 

1.线程同步机制

在多线程编程中,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何时刻,最多有一个线程访问,以保证数据的完整性。

锁是实现线程同步的一种常见手段。

2.实现方法

2.1 同步代码块

得到对象的锁,操作同步代码:

synchronized (对象){
    //需要被同步的代码
}
2.2 同步方法

放在方法声明中:

public synchronized void fun(){
    //需要被同步的代码
}

3.互斥锁

Java中引入了互斥锁的概念来保证共享数据操作的完整性。每个对象都有一个互斥锁的标记,这个标记用来确保在任一时刻,只有一个线程访问该对象。当一个对象用Synchronized 修饰时,表明该对象在任一时刻只能由一个线程访问。

但是同步也有局限性,那就是程序执行效率降低。比如一个本来一条路(有多个车道)可以自由通行,现在把它堵上了,安了一个卡口,一次就能通过一辆车,那么效率不就降低了。

如果同步的方法是非静态的,这时锁可以时this或者是其他对象。这里要注意,多线程操作每一个线程必须是同一个对象,如果是多个的话锁不就失效了嘛。比如说我们有一个Cat类,我们new了两个对象,一个cat1,一个cat2,这就不行。要new一个cat,然后用这个cat.start()两次,开两个线程才可以。

如果同步的方法是静态的,这时锁为当前类的本身,不能是this。

4.释放锁

我们不能只拿到了锁,用完了还要释放。下面是释放锁的几种途径:

1.当前线程的同步方法、同步代码块执行结束

2.当前线程在同步方法、同步代码块中遇到了break、return

3.当前线程在同步方法、同步代码块中出现了为处理的Error或Exception,导致异常结束

4.当前线程在同步方法、同步代码块中执行了线程对象的wait()方法,当前线程暂停,并释放锁

下面几种操作不会释放锁:

1.线程执行同步方法或同步代码块时,程序调用Thread.sleep()、Thread.yield()方法,暂停当前线程的执行,不会释放锁

2.线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,不会释放锁

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

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

相关文章

fastAPI教程:数据库操作

FastAPI 六、数据库操作 FastAPI支持操作各种数据库&#xff0c;但本身并没有内置关于任何数据库相关的模块。因此我们可以根据需求使用任何数据库&#xff0c;包括关系型&#xff08;SQL&#xff09;数据库&#xff0c;例如&#xff1a;PostgreSQL、MySQL、SQLite、Oracle、…

【AGC005D】~K Perm Counting(计数抽象成图)

容斥原理。 求出f(m) &#xff0c;f(m)指代至少有m个位置不合法的方案数。 怎么求&#xff1f; 注意到位置为id&#xff0c;权值为v ,不合法的情况&#xff0c;当且仅当 v idk或 v id-k 因此&#xff0c;我们把每一个位置和权值抽象成点 &#xff0c;不合法的情况之间连一…

【JVM】基础篇

1 初识JVM 1.1 什么是JVM JVM 全称是 Java Virtual Machine&#xff0c;中文译名 Java虚拟机。JVM 本质上是一个运行在计算机上的程序&#xff0c;他的职责是运行Java字节码文件。 Java源代码执行流程如下&#xff1a; 分为三个步骤&#xff1a; 1、编写Java源代码文件。 …

自动驾驶系列—深度剖析自动驾驶芯片SoC架构:选型指南与应用实战

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

认知杂谈74《远离渣女陷阱,拥抱健康情感》

内容摘要&#xff1a; 渣女在感情中使用甜言蜜语陷阱&#xff0c;利用男性渴望理解和关爱的心理&#xff0c;通过虚假承诺和情感操控来获得利益。 男性易陷入这种陷阱&#xff0c;因为他们可能因压力大、感性而易受感动。为了避免这种情况&#xff0c;男性需要辨别言行一致性&a…

【含文档】基于Springboot+Vue的国风彩妆网站(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

软件设计之SSM(4)

软件设计之SSM(4) 路线图推荐&#xff1a; 【Java学习路线-极速版】【Java架构师技术图谱】 尚硅谷新版SSM框架全套视频教程&#xff0c;Spring6SpringBoot3最新SSM企业级开发 资料可以去尚硅谷官网免费领取 学习内容&#xff1a; 基于配置类方式管理Bean 完全注解开发第三…

共模电感工作原理:【图文讲解】

共模电感&#xff0c;相信做电源较多的朋友用的比较多&#xff0c;而做消费级产品的朋友或许用的不是那么的多。但是还是有必要了解了解。 先上图&#xff0c;看看它长什么样子&#xff1a; &#xff08;实物图&#xff09; &#xff08;结构图&#xff09; 很显然&#xff0…

【Ubuntu】安装常用软件包-mysql

我的几个服务是部署在docker的同一个网络里&#xff0c;这样相互访问就可以通过docker容器的名字访问&#xff0c;比如容器A访问容器B&#xff0c;就可以http://B:8080/xxx 这样访问&#xff0c;不用关心ip是多少。 所以mysql前面文章给安装到主机里&#xff0c;感觉有点坑自己…

02.usePrevious

在 React 开发中&#xff0c;有时我们需要访问组件的前一个状态或属性。这在进行比较、动画或其他需要历史数据的操作时特别有用。usePrevious 钩子提供了一种简单而有效的方式来存储和访问前一个值。以下是如何实现和使用这个自定义钩子&#xff1a; const usePrevious valu…

【数据类型】C和C++的区别

文章目录 一、字符串二、布尔类型 bool三、数据的输入和输出 C和C在数据类型上打区别不大&#xff0c;下面就二者在这方面的部分区别做比较。 一、字符串 C语言和C在字符串的定义和书写风格上略有差异。 C风格字符串&#xff1a; char str[]"hello";C风格字符串 st…

社交内容电商中的新机遇:2+1链动模式AI智能名片商城小程序

在当今的电商世界里&#xff0c;社交内容电商正蓬勃发展。这种模式基于高质量内容&#xff0c;将有着共同兴趣爱好的用户聚集起来形成社群&#xff0c;随后引导用户进行裂变式的传播与交易。无论是像微信、微博、快手、抖音、今日头条这样的平台形式&#xff0c;还是网红、“大…

算法笔记(四)——模拟

文章目录 替换所有的问号提莫攻击Z字形变换外观数列数青蛙 模拟算法就是根据题目的要求&#xff0c;题目让干神马就做神马&#xff0c;一步一步来 替换所有的问号 题目&#xff1a;替换所有的问号 思路 从左到右遍历整个字符串&#xff0c;找到问号之后&#xff0c;就⽤ a ~ z…

QT系统学习篇(2)- Qt跨平台GUI原理机制

一、Qt工程管理 新建项目&#xff1a; 我们程序员新建项目对话框所有5类项目模板 Application: Qt的应用程序&#xff0c;包含Qt Quick和普通窗口程序。 Library: 它可以创建动态库、静态库、Qt Creator自身插件、Qt Quick扩展插件。 其他项目: 创建单元测试项目、子目录项目…

自动驾驶系列—自动驾驶MCU架构全方位解析:从单核到多核的选型指南与应用实例

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

五子棋双人对战项目(3)——匹配模块

一、分析需求 二、约定前后端接口 三、实现游戏大厅页面&#xff08;前端代码&#xff09; 四、实现后端代码 五、线程安全问题 六、忙等问题 一、分析需求 需求&#xff1a;多个玩家&#xff0c;在游戏大厅进行匹配&#xff0c;系统会把实力相近的玩家匹配到一起。 要想实…

使用cmake配置pcl环境

项目文件在https://pan.quark.cn/s/d347f72c7432 文件中包含CMakeLists.txt&#xff0c;一个pcd文件&#xff0c;一个cpp源文件。 这里的话&#xff0c;首先你需要下载好cmake软件&#xff0c;并将其添加到环境变量。 CMakeLists.txt文件内容如下 cmake_minimum_required(VER…

「漏洞复现」EDU 某智慧平台 PersonalDayInOutSchoolData SQL注入漏洞

0x01 免责声明 请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;作者不为此承担任何责任。工具来自网络&#xff0c;安全性自测&#xff0c;如有侵权请联系删…

鸿蒙媒体开发系列16——图像变换与位图操作

如果你也对鸿蒙开发感兴趣&#xff0c;加入“Harmony自习室”吧&#xff01;扫描下方名片&#xff0c;关注公众号&#xff0c;公众号更新更快&#xff0c;同时也有更多学习资料和技术讨论群。 1、概述 图片处理指对PixelMap进行相关的操作&#xff0c;如获取图片信息、裁剪、缩…