Java线程概念详解

news2024/11/29 22:49:04

线程

在这里插入图片描述

概念

1.程序:未解决某种问题,使用计算机语言编写的一些列指令(代码)的集合

2.进程:正在运行的程序(被加载到内存中),是操作系统进行资源分配的最小单位

3.线程:进程可以进一步细化为线程(比进程更小)且线程是隶属于进程的,是操作系统执行的最小的执行单元 也是cpu进行任务调度的最小单位

  • 如 :运行的QQ也是一个进程,操作系统就会为这个进程分配资源 一个聊天窗口就是一个线程,线程隶属于进程

tips:早期是没有线程的,是以进程为单位执行的,进程的单位比较大,当一个进程运行时,其他进程就不能执行了,所以后来,将进程中的多个任务细化为线程,cpu的执行单位,也是从进程进化为更小的线程

总结

  1. 一个进程可以包含多个线程
  2. 一个线程只能隶属于一个进程,线程不能脱离进程单独独立运行
  3. 一个进程中至少有一个线程,即主线程,javamian方法就是用来启动主线程
  4. 在主线程中可以创建并启动其他线程,所有线程都共享进程的内存资源
  5. 所有线程都共享进程资源

Thread类

JavaThread表示线程,提供了许多的方法,来对线程的控制,可以通过继承Thread 类来实现线程

Thread常用方法

  • Thread.currentThread();
    • 获取当前运行的线程
  • run();
    • 线程要执行的任务
  • start();
    • 启动Java线程
  • setName(String name);
    • 设置线程名字
  • (String)getName();
    • 获取线程名字
  • getPriority();
    • 获取线程优先级
  • setPriority();
    • 设置线程优先级 1~10一般线程默认优先 5
  • sleep(long ms);
    • 设置线程休眠
  • join();
    • 让其他线程等待这个线程结束后,其他线程再执行

Thread构造方法

  • new Thread(Runnable runnable);
    • 接受一个任务对象
  • new Thread(Runnable runnable,String name);
    • 接受一个对象 并为对象设置名字

使用上面方法进行实例

线程1
public class MyThread extends Thread{

    //重写run方法,在run中执行我们要执行的方法
    @Override
    public void run() {
        for(int i=0;i<10000;i++){
            System.out.println("循环main"+i);
        }
    }

}
线程2
public class MyThread2 extends Thread {
    @Override
    public void run() {
        for(int i=0;i<10000;i++){
            System.out.println("循环main2"+i);
        }
    }
}
public class 线程 {
    public static void main(String[] args) {
        for(int i=0;i<10000;i++){
            System.out.println("循环1 "+i);
        }
        for(int i=0;i<10000;i++){
            System.out.println("循环2 "+i);
        }
        for(int i=0;i<10000;i++){
            System.out.println("循环3 "+i);
        }
        for(int i=0;i<10000;i++){
            System.out.println("循环4 "+i);
        }
        /*
        这样不管怎么执行都是单线程,从上到下依次执行,

        所以如果想在java程序中有几件不想管的事件同时执行
         可以在java中创建线程,把一些需要执行的任务放在线程中执行,
         这样就拥有让cup执行的权利
         */
        MyThread myThread = new MyThread();
        //调用start方法让程序多线程进行,重写run方法但不能调用run,不然只是普通方法的调用,依然是单线程
        myThread.start();
        MyThread2 myThread2 = new MyThread2();
        myThread2.start();

    }

}

image-20231207203645612

观察结果 可知 MyThreadMyThread2是同时进行的

Runnable接口

Java中我们也可以实现Runnable接口来进行对线程的实现

思路.

  • 创建一个类 实现Runnable接口 重写run方法

  • 在main函数使用Thread构造方法传入Runnable对象

  • public class MyTask implements Runnable{
        @Override
        public void run() {
            for(int i=0;i<10;i++){
                System.out.println("啊");
            }
        }
    }
    
  • MyTask myTask = new MyTask();
           //创建一个线程
           Thread thread = new Thread(myTask);
    

Callable接口

Java中也可以实现Callable接口 重写 call()方法 来对线程的实现

思路.

  • 重写call()方法 call()方法有返回值 可以抛出异常,还可以处理不同类型
  • 依然使用Thread构造方法来创建一个线程

关于线程的其他概念

线程生命周期

从线程到销毁期间经历五个状态

image-20231029190539052

守护线程(也是线程的一种)

  • setDaemon();如果一个**线程守护线程**,那么它会等待java中其他线程任务结束后,自动终止
  • 守护线程是为其他线程提供服务的,eg:jvm中的垃圾回收机制,就是一个守护线程

多线程

在一个应用程序中,存在多个线程,不同线程可以并行的执行任务

*操作系统线程任务调度算法

  1. 先来先服务调度算法
  2. 短作业优先调度算法
  3. 优先级调度算法
  4. 高响应比优先调度算法
  5. 时间片轮转调度算法
  6. 多级反馈队列调度算法(集合前几种算法的优点)

对线程进行加锁

分析

  • 多线程的优点
    • 提高程序的处理能力
    • 提高CPU的 利用率
  • 缺点
    • 线程也是需要占用内存资源和CPU资源
    • 多个线程对同一个共享资源进行访问,会出现线程安全问题

对于内存资源与CPU资源我们可以通过不断增加内存来解决

对于线程安全问题 我们则需要对 线程进行加锁

synchronized

synchronized 修饰代码块需要加一个同步对象 synchronized(同步对象)

同步对象要求

  • 多线程用到的对象必须是同一个对象
  • 可以是java类中任何类对象.
  • 作用:用来记录有没有线程进入到同步代码块中

修饰方法

  • 锁不需要我们提供,会默认提供锁对象
  • synchronized如果修饰的是非静态方法,锁的对象是this
  • 如果是静态方法,锁的对象是Class的对象 (一个类只能有一个对象)

修饰代码块例子

package day17;

public class PrintNums implements Runnable{
    //实现线程的交替打印
    int num=100;
    Object object = new Object();
    @Override
    public void run() {
        while(true){
            synchronized (object){
                object.notify();//唤醒线程
                if(num==0){
                    break;
                }
                System.out.println(Thread.currentThread().getName()+"."+num+".");
                num--;
                try {
                    object.wait();//线程等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
package day17;

public class TestPrintNums {
    public static void main(String[] args) {
        PrintNums printNums = new PrintNums();
        Thread t1 = new Thread(printNums,"1");
        Thread t2 = new Thread(printNums,"2");
        Thread t3 = new Thread(printNums,"3");
        t1.start();
        t2.start();
        t3.start();
    }
}

image-20231207211850022

于是我们实现了交替打印 每次只能进入一个线程

修饰方法(同步对象会有默认的)

  1. 锁不需要我们提供,会默认提供对象锁
  2. synchronized如果修饰的是非静态方法,锁的对象是this

synchronized如果修饰的是静态方法,锁的对象是类的Class对象,一个类只有 一个对象

  • 如果是非静态方法,那么同步对象是this(如果是非静态对象,我们可以使用Runnable创建线程方法)

  • 如果是静态方法,所得对象是当前类的Class对象

  • 当前类的Class对象:一个类加载到内存后会为这个类创建唯一的Class类的对象

  • Class类实例表示正在运行的Java应用程序中的类和接口

  • 修饰静态方法
    public class SellTicket extends Thread {
        static int counts = 10;//10张票
        static Object object = new Object();
    
        @Override
        public void run() {
    
            while (counts > 0) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                sellTicket();
            }
        }
    
        public static synchronized void sellTicket() {
            if(counts>0){
                System.out.println(Thread.currentThread().getName()+"买了"+counts+"张票");
                --counts;
            }
        }
    }
    public class Test {
        public static void main(String[] args) {
            SellTicket t1 = new SellTicket();
            t1.setName("窗口1");
            SellTicket t2 = new SellTicket();
            t2.setName("窗口2");
    
            t1.start();
            t2.start();
        }
    }
    

    image-20231209231353289

  • 修饰非静态方法
    public class SellTickets2 implements Runnable{
    
        int t=20;//票数
    
        @Override
        public void run() {
            while(t>0){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                sell2();
            }
        }
        public synchronized void sell2(){
            if(t>0){
                System.out.println(Thread.currentThread().getName()+"买了"+t+"张票");
                --t;
            }
        }
    }
    
    public class Test2 {
        public static void main(String[] args) {
            SellTickets2 sellTickets2 = new SellTickets2();
            Thread t1 = new Thread(sellTickets2,"窗口1");
            Thread t2 = new Thread(sellTickets2,"窗口2");
    
            t1.start();
            t2.start();
        }
    }
    

    image-20231209231446179

ReentrantLock类加锁

  • 只能对某一代码块进行加锁,不能对整个方法加锁
  • 加锁方法如下
ReentrantLock r = new ReentrantLock();//创建 ReentrantLock对象
r.lock();<---------|//加锁
                   |
  .............    |------被锁部分(一次只进去一个线程)
                   |
r.unlock();<-------|//解锁

tips:r.unlock();最好写在finally{};代码块中,保证发生异常时,也能够解锁;

synchronized与ReentrantLock的区别

  1. synchronized是一个关键字,ReentrantLock是一个类

  2. synchronized修饰代码块和方法,ReentrantLock只能修饰代码块

  3. synchronized可以隐式的加锁和释放锁,运行出现异常可以自动释放锁

    ReentrantLock需要手动加锁和释放锁,建议在finally代码中释放锁

常用的三个方法 wait ``notify notifyAll

  • wait();方法使当前线程进入等待状态,直到另一个线程调用该对象的notify()notifyAll()方法来唤醒它

  • notify();方法唤醒在该对象上调用wait()方法进入等待状态的一个线程,如果有多个线程在等待,则只会唤醒其中一个线程。

  • notifyAll();方法唤醒在该对象上调用wait()方法进入等待状态的所有线程。

    tips:1.都是Object类中定义的方法

    ​ 2.三个方法必须在同步代码块中使用

    ​ 3.这三个方法必须通过为锁的对象调用

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

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

相关文章

整合,降价,官司……2023休闲零食行业大变局

休闲零食行业正从暗战走向明战。 11月27日&#xff0c;宁波广源聚亿投资有限公司&#xff08;以下简称“广源聚亿”&#xff09;因被投企业宜春赵一鸣食品科技有限公司&#xff08;以下简称“赵一鸣”&#xff09;在双方合作期内&#xff0c;刻意隐瞒公司重大事项&#xff0c;…

Matlab数学建模算法之小波神经网络详解

&#x1f517; 运行环境&#xff1a;Matlab &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 &#x1f510;#### 防伪水印——左手の明天 ####&#x1f510; &#x1f497; 大家…

PHP使用mkcert本地开发生成HTTPS证书 PhpEnv集成环境

PHP使用mkcert本地开发生成HTTPS证书 PhpEnv集成环境 前言一、介绍 mkcert二、安装/使用 mkcert1. 安装2. 使用 总结 前言 本地开发时有些功能只有在 https 证书的情况下才能使用, 例如一些 Web API 一、介绍 mkcert Github地址 mkcert 是一个制作本地可信开发证书的简单工具。…

基于以太坊的智能合约开发Solidity(事件日志篇)

//声明版本号&#xff08;程序中的版本号要和编译器版本号一致&#xff09; pragma solidity ^0.5.17; //合约 contract EventTest {//状态变量uint public Variable;//构造函数constructor() public{Variable 100;}event ValueChanged(uint newValue); //事件声明event Log(…

无人零售店,凭借黑科技引领,它的前景如何?

无人零售店&#xff0c;凭借黑科技引领&#xff0c;它的前景如何&#xff1f; 近年来&#xff0c;无人新零售行业快速兴起&#xff0c;引起了广泛的关注和兴趣。尤其是在疫情之后&#xff0c;人们才真正认识到了无人零售的概念。如今&#xff0c;无人零售行业正在以直线的方式高…

U2 文法和语言

文章目录 一、预备知识1、字母表和符号串2、符号串形式定义3、符号串相等4、延申 二、文法1、 一些概念2、文法的定义3、推导的形式定义4、规范推导5、语言的形式定义6、递归文法7、BNF范式总结 三、短语、简单短语和句柄四、语法树(推导树)1、概念2、语法树推导--句型的推导3、…

打造Github首页的动态飞线效果

一、导语 Github首页的地球动态飞线&#xff0c;大家都比较熟悉吧 二、分析 由大量随机的3点构造出贝塞尔曲线&#xff0c;然后开始从起点到终点的飞行后&#xff0c;然后再从起点到终点的消失&#xff0c;就此完成整个过程 三、基础代码 createCurve(startPoint, endPoint…

爬虫解析-jsonpath (六)

jsonpath只能解析本地文件 jsonpath的使用&#xff1a; obj json.load(open(.json文件,r,encodingutf-8))place_name jsonpath.jsonpath(obj, json语法) 目录 1.安装jsonpath 2.Xpath和jsonpath的语法对比 练习&#xff1a;使用jsonpath解析JSON文件 3.使用jsonpath抓取…

论文代码阅读:TGN模型训练阶段代码理解

文章目录 [toc] TGN模型训练阶段代码理解论文信息代码过程手绘代码训练过程compute_temporal_embeddingsupdate_memoryget_raw_messagesget_updated_memoryself.message_aggregator.aggregateself.memory_updater.get_updated_memoryMemoryget_embedding_moduleGraphAttentionE…

从线性回归到神经网络

一、线性回归关键思想 1、线性模型 2、基础优化算法 二、线性回归的从零开始实现 在了解线性回归的关键思想之后&#xff0c;我们可以开始通过代码来动手实现线性回归了。在这一节中&#xff0c;我们将从零开始实现整个方法&#xff0c;包括数据流水线、模型、损失函数和小批量…

深度探索Linux操作系统 —— 从内核空间到用户空间

系列文章目录 深度探索Linux操作系统 —— 编译过程分析 深度探索Linux操作系统 —— 构建工具链 深度探索Linux操作系统 —— 构建内核 深度探索Linux操作系统 —— 构建initramfs 深度探索Linux操作系统 —— 从内核空间到用户空间 文章目录 系列文章目录一、Linux操作系统加…

Java IO流(六)(字符流FileReader和FileWriter)

字符流 字符流的底层其实就是字节流 字符流字节流字符集 特点 输入流&#xff1a;一次读一个字节&#xff0c;遇到中文时&#xff0c;一次读多个字节 使用场景 对于纯文本文件进行读写操作 FileReader类 ①创建字符输入流对象 构造方法 说明 public FileReader(File f…

Configuring environment||ROS2环境配置

Goal: This tutorial will show you how to prepare your ROS 2 environment. Tutorial level: Beginner Time: 5 minutes ROS 2 relies on the notion &#xff08;concept&#xff09;of combining workspaces using the shell environment. “Workspace” is a ROS term …

读书笔记:《股票量化交易的七个策略》

从长远来看&#xff0c;基本面最重要&#xff1b;从短期来看&#xff0c;价格和情绪最重要。在别人贪婪时恐惧&#xff0c;在别人恐惧时贪婪。 相对强弱指数策略【趋势反转】 相对强弱指数&#xff08;Relative Strength Index&#xff0c;RSI&#xff09; RSI的取值范围在0到…

亚马逊云科技re_Invent 2023产品体验:亚马逊云科技产品应用实践 国赛选手带你看Elasticache Serverless

抛砖引玉 讲一下作者背景&#xff0c;曾经参加过国内世界技能大赛云计算的选拔&#xff0c;那么在竞赛中包含两类&#xff0c;一类是架构类竞赛&#xff0c;另一类就是TroubleShooting竞赛&#xff0c;对应的分别为AWS GameDay和AWS Jam&#xff0c;想必也有朋友玩过此类竞赛&…

【C++】输入输出流 ⑥ ( cout 标准输出流对象 | cout 常用 api 简介 | cout.put(char c) 函数 )

文章目录 一、cout 标准输出流对象1、cout 标准输出流对象简介2、cout 常用 api 简介 二、cout.put(char c) 函数1、cout.put(char c) 函数 简介2、代码示例 - cout.put(char c) 函数 一、cout 标准输出流对象 1、cout 标准输出流对象简介 cout 是 标准输出流 对象 , 是 ostrea…

Redis的概念与常见命令

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…

新版Spring Security6.2架构 (一)

Spring Security 新版springboot 3.2已经集成Spring Security 6.2&#xff0c;和以前会有一些变化&#xff0c;本文主要针对官网的文档进行一些个人翻译和个人理解&#xff0c;不对地方请指正。 整体架构 Spring Security的Servlet 支持是基于Servelet过滤器&#xff0c;如下…

永磁同步电机反电动势系数怎么算?磁链强度怎么算?转矩系数怎么算?

在进行永磁同步电机simulink仿真时&#xff0c;一个关键参数就是永磁体磁链强度&#xff0c; 实际上在simulink中&#xff0c;永磁体磁链强度/反电动势系数/转矩系数这三个是放一起的&#xff0c;这是因为他们都可互相算出来。 Torque constat (Nm/A) 转矩系数 1.5 * Np *…

Java 匿名内部类使用的外部变量,为什么一定要加 final?

问题描述 Effectively final Java 1.8 新特性&#xff0c;对于一个局部变量或方法参数&#xff0c;如果他的值在初始化后就从未更改&#xff0c;那么该变量就是 effectively final&#xff08;事实 final&#xff09;。 这种情况下&#xff0c;可以不用加 final 关键字修饰。 …