多线程与高并发编程一

news2024/9/22 5:39:00

文章目录

  • 一、故事背景
  • 二、知识点主要构成
    • 1、线程的概念
    • 2、启动方式
      • 2.1、继承Thread类 重写run方法
      • 2.2、实现Runnable接口 重写run方法
      • 2.3、实现Callable 重写call方法 配合FuterTask获取线程结果
    • 3、常用方法
      • start()方法:
      • run()方法:
      • sleep(long millis)方法:
      • join()方法:
      • interrupt()方法:
      • isAlive()方法:
    • 4、synchronized
      • 4.1、锁升级
      • 4.2、锁消除
      • 4.3、锁粗化
    • 5、线程同步
  • 三、总结提升

一、故事背景

最近在学习多线程与高并发编程系列的相关知识,这里总结出几点给大家分享一下,

二、知识点主要构成

1、线程的概念

一个程序进入内存被称之为进程;同一个进程内部,有多个任务并发执行的需求,(比如,一边计算,一边接受网络数据,一边刷新页面)线程共享进程的内存空间,但是不共享计算;进程是静态的,程序进入内存,分配对应资源(内存空间),进程进入内存,同时产生一个主线程;线程是动态的,可执行的计算单元。

2、启动方式

2.1、继承Thread类 重写run方法

public class ThreadTest extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+"运行了"+i);
        }
    }

    public static void main(String[] args) {
        ThreadTest threadTest = new ThreadTest();
        Thread thread1 = new Thread(threadTest);
        thread1.start();
    }
}

2.2、实现Runnable接口 重写run方法

public class RunnableTest implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+":hello thead"+i);
        }
    }
    /**
     * 多线程第二种启动方式:
     * 1.自己定义一个类去实现 runnable接口
     * 2.重新run方法--线程执行的代码
     * 3.创建自己的对象
     * 4.创建一个Thread类的对象 并开启线程
     */
    public static void main(String[] args) {
        RunnableTest runnableTest = new RunnableTest();
        // 线程1
        Thread t1=new Thread(runnableTest);
        t1.start();
        t1.setName("线程1");
        // 线程2
        Thread t2=new Thread(runnableTest);
        t2.start();
        t2.setName("线程2");
    }
}

2.3、实现Callable 重写call方法 配合FuterTask获取线程结果

public class CallableTest implements Callable<Integer> {
    @Override
    public Integer call() {
        int sum=0;
        for (int i = 0; i < 100; i++) {
            sum=sum+i;
        }
        return sum;
    }

    /**
     * 多线程第三种启动方式:
     * 解决:多线程其他两种没有返回值
     * 特点:可以获取多线程的运行结果
     *
     * 1.创建一个类 实现Callable接口
     * 2.重写 call(有返回值表示结果)
     * 3.创建任务对象
     * 4.创建 FutureTask对象(管理多线程结果)
     * 5.创建Thread类并启动,
     */
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CallableTest callableTest = new CallableTest();
        FutureTask<Integer> futureTask = new FutureTask(callableTest);
        Thread thread = new Thread(futureTask);
        thread.start();
        System.out.println(futureTask.get());
    }
}

3、常用方法

start()方法:

方法签名:public synchronized void start()
作用:启动线程并调用线程的run()方法。run()方法中定义了线程的实际执行逻辑。

Thread thread = new MyThread(); // MyThread是继承自Thread的类
thread.start();

run()方法:

方法签名:public void run()
作用:定义线程的执行逻辑。需要在子类中重写该方法,以实现自定义的线程行为。
示例:

class MyThread extends Thread {
    public void run() {
        // 线程的执行逻辑
    }
}

sleep(long millis)方法:

方法签名:public static native void sleep(long millis) throws InterruptedException
作用:让当前线程睡眠指定的毫秒数,暂时释放CPU资源。

try {
    Thread.sleep(1000); // 线程睡眠1秒
} catch (InterruptedException e) {
    // 处理异常
}

join()方法:

方法签名:public final synchronized void join() throws InterruptedException
作用:等待调用该方法的线程执行完毕后再继续执行当前线程。

Thread thread = new MyThread();
thread.start();
try {
    thread.join(); // 等待thread线程执行完毕
} catch (InterruptedException e) {
    // 处理异常
}

interrupt()方法:

方法签名:public void interrupt()
作用:中断线程的执行,会设置线程的中断状态。线程可以通过检查中断状态来自行决定是否中断。

Thread thread = new MyThread();
thread.start();
thread.interrupt(); // 中断thread线程的执行

isAlive()方法:

方法签名:public final native boolean isAlive()
作用:判断线程是否还活着(是否在执行或者等待状态)。

Thread thread = new MyThread();
thread.start();
boolean alive = thread.isAlive(); // 检查thread线程是否还活着

4、synchronized

在JDK 1.6后,Jvm为了提高锁的获取与释放效率对(synchronized )进行了优化,引入了 偏向锁 和 轻量级锁 ,
从此以后锁的状态就有了四种。

4.1、锁升级

在这里插入图片描述
在锁对象的对象头里面有一个 threadid 字段,在第一次访问的时候 threadid 为空,jvm 让其持有偏向锁,并将 threadid 设置为其线程 id,再次进入的时候会先判断 threadid 是否与其线程 id 一致,如果一致则可以直接使用此对象,如果不一致,则升级偏向锁为轻量级锁,通过自旋循环一定次数来获取锁,执行一定次数之后,如果还没有正常获取到要使用的对象,此时就会把锁从轻量级升级为重量级锁。
通俗来说就是:对象刚刚被new出来,没有任何人给他上锁,处于无锁状态,此时来了一个线程,升级为偏向锁,如果没有其他线程和其进行抢锁,那么下次直接就能获取锁,如果有其他线程和其进行争抢,那么就撤销偏向锁,升级为轻量级锁,线程在自己的线程栈中生成LockRecord,用CAS操作将markword设置为指向自己这个线程LR指针,设置成功者得锁,在进行CAS的过程中是一直在占用CPU的资源的,默认在进行10次自选操作之后升级为重量级锁,此时由操作系统来给线程分配锁,分配之后进入锁的队列中进入阻塞状态,此时是不消耗CPU资源的,等CPU什么时候有时间了线程进行执行状态;
在这里插入图片描述

4.2、锁消除

public void add(String str1,String str2){
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(str1).append(str2);
}

StringBuffer是线程安全的,因为它的关键方法都是被synchronized修饰过的,单是看上面的代码,会发现stringBuffer这个引用只会在add方法中调用,不可能被其他线程引用,(因为是局部变量,线程栈私有的)因此stringBuffer是不可能共享的资源,JVM会自动消除StringBuffer对象内部的锁;

4.3、锁粗化

public String test(String str) {
        int i = 0;
        StringBuffer stringBuffer = new StringBuffer();
        while (i < 100) {
            stringBuffer.append(str);
            i++;
        }
        return stringBuffer.toString();
}

JVM会检测到这样一连串的操作都对同一个对象加锁,while循环内100次执行append,没有锁粗化的就要进行100次加锁、解锁的操作,此时JVM就会将加锁的范围粗化到这一连串操作的外部,while循环体外,使得这一连串操作只需要加一次锁即可;

5、线程同步

Java实现生产者消费者问题

三、总结提升

以往的经验中,只要用到synchronized就以为它已经成为了重量级锁。在jdk1.2之前确实如此,后来发现太重了,消耗了太多操作系统资源,所以对synchronized进行了优化。以后可以直接用,至于锁的力度如何,JVM底层已经做好了我们直接用就行。

如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏哦。

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

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

相关文章

【HCIP】企业网三层架构实验

题目&#xff1a; 拓扑图 配置 LSW1 //链路聚合 [lsw3]interface Eth-Trunk 1 [lsw3-Eth-Trunk1]trunkport GigabitEthernet 0/0/3 0/0/4 [lsw3-Eth-Trunk1]q [lsw3]vlan batch 1 2 [lsw3]interface Eth-Trunk 1 [lsw3-Eth-Trunk1]port link-type trunk [lsw3-Eth-Trunk1]port…

docker中bridge、host、container、none四种网络模式简介

一.bridge模式 1.简介 2.演示 &#xff08;1&#xff09;运行两个容器&#xff0c;不指定网络模式情况下默认是bridge模式 &#xff08;2&#xff09;在主机中自动生成了两个veth设备 &#xff08;3&#xff09;查看两个容器的IP地址 &#xff08;4&#xff09;可以自定义…

基于图卷积网络的知识嵌入8.21

基于图卷积网络的知识嵌入 摘要介绍 摘要 近年来&#xff0c;围绕图卷积网络&#xff08;GCN&#xff09;这一主题出现了大量的文献。如何有效地利用复杂图中丰富的结构信息&#xff08;例如具有heterogeneous types of entities and relations(异构实体和关系类型) 的知识图谱…

深入理解ForkJoin

任务类型 线程池执行的任务可以分为两种&#xff1a;CPU密集型任务和IO密集型任务。在实际的业务场景中&#xff0c;我们需要根据任务的类型来选择对应的策略&#xff0c;最终达到充分并合理地使用CPU和内存等资源&#xff0c;最大限度地提高程序性能的目的。 CPU密集型任务 …

【快速解决方案】浏览器的安全策略不允许通过 file:// 协议直接加载外部文件(最省事的方法)

目录 问题摘要 解决办法 检验结果 问题摘要 Failed to load resource: net::ERR_FILE_NOT_FOUND&#x1f308; Cute Code Editor &#x1f308;.html:162 Fetch API cannot load file:///D:/%E6%A1%8C%E9%9D%A2/%E4%B8%83%E5%A4%95%E5%BF%AB%E4%B9%90/index.txt. URL scheme …

RK3399平台开发系列讲解(内核调试篇)内核中内存泄漏的调试

🚀返回专栏总目录 文章目录 一、Linux 内核内存泄漏二、如何观测内核内存泄漏?三、kmemleak 工具沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 内核内存泄漏往往都会是很严重的问题,那么,我们该如何判断内存泄漏是否是内核导致的呢? 一、Linux 内核内存泄漏 …

003-Nacos 2.1.x 注册实例源码分析

目录 Nacos 2.1.X注册实例入口接口流程Client 注册 事件处理 服务订阅入口 Nacos 2.1.X 注册实例 入口 com.alibaba.nacos.naming.remote.rpc.handler.InstanceRequestHandler#handleService service Service.newService(request.getNamespace(), request.getGroupName(), r…

计算机网络————IP数据报的首部各字段详解(很重要)

目录 1. IP数据报的介绍2. 首部的固定部分的各字段说明2.1 Version&#xff08;版本&#xff09;2.2 IHL&#xff08;首部长度&#xff09;2.3 Type of service&#xff08;区分服务&#xff09;2.4 Total Length&#xff08;总长度&#xff09;2.5 Identification&#xff08;…

企业级即时通讯协作和移动应用管理平台哪个品牌好?

在竞争激烈的商业环境下&#xff0c;高效的企业通讯和协作变得至关重要。WorkPlus作为领先的品牌&#xff0c;专注于提供企业级即时通讯协作和移动应用管理平台。本文将介绍WorkPlus如何成为企业实现协同工作、高效沟通和流程管理的理想解决方案。 一、全面协作加速工作流程&am…

二、1.保护模式

访问外部硬件有两个方式&#xff1a; 将某个外设的内存映射到一定范围的地址空间中&#xff0c; CPU 通过地址总线访问该内存区域时会落到外设 的内存中&#xff0c;这种映射让 CPU 访问外设的内存就如同访问主板上的物理内存一样外设是通过 IO 接口与 CPU 通信的&#xff0c;…

BDA初级分析——民宿投资决策影响因素分析

实战作业: 民宿投资决策影响因素分析如今&#xff0c;出门旅行住民宿已经不是一个新鲜话题&#xff0c;而且民宿品牌也是层出不穷.作为一名旅行服务业的数据分析师&#xff0c;我们以Airbnb北京的民宿为例&#xff0c;对其进行数据分析&#xff0c;探索什么类型的民宿价格更高?…

Eltima USB Network Gate 10.0 Crack

USB Network Gate -通过网络共享USB 设备 USB Network Gate (前身为以太网USB控制器USB) 轻松的通过网络(Internet/LAN/WAN)分享您的一个或者多个连接到您计算机的USB设备。 无论您身处异国还是近在隔壁办公室&#xff0c;您都可以轻松使用远程扫描仪、打印机、摄像头、调制解…

从零构建深度学习推理框架-9 再探Tensor类,算子输入输出的分配

再探Tensor类&#xff1a; 第二节中我们编写的Tensor类其实并不能满足我们的使用需要&#xff0c;我们将在这一节以代码阅读的方式来看看一个完全版本的Tensor应该具备怎样的要素&#xff0c;同时我们对Tensor类的分析来看看在C中一个设计好的类应该是怎么样的。 Tensor<fl…

K8s学习笔记3

Kubernetes功能&#xff1a; Kubernetes是一个轻便的可扩展的开源平台&#xff0c;用于管理容器化应用和服务。通过Kubernetes能够进行应用的自动化部署和扩缩容。在Kubernetes中&#xff0c;会将组成应用的容器组合成一个逻辑单元以更易管理和发现。Kubernetes积累了作为Goog…

打怪升级之从零开始的网络协议

序言 三个多月过去了&#xff0c;我又来写博客了&#xff0c;这一次从零开始学习网络协议。 总的来说&#xff0c;计算机网络很像现实生活中的快递网络&#xff0c;其最核心的目标&#xff0c;就是把一个包裹&#xff08;信息&#xff09;从A点发送到B点去。下面是一些共同的…

面试-快速学习计算机网络-UDP/TCP

1. OSI四层和七层映射 区别&#xff1a; 应用层&#xff0c;表示层&#xff0c;会话层合并为了应用层数据链路层和物理层合并为了网络接口层 2. TCP和UDP的区别&#xff1f; 总结&#xff1a; 1 . TCP 向上层提供面向连接的可靠服务 &#xff0c;UDP 向上层提供无连接不可靠服…

验证二叉搜索树

给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。 示例 1&#xff1a; 输…

8.21summary

计划部分完成&#xff0c;复习暂未完成

Linux环境下交叉编译环境安装、编译和运行

Win11主机上安装虚拟机&#xff0c;虚拟机内运行Ubuntu20.04&#xff0c;为了能够在本地电脑&#xff08;Win11&#xff09;上开发测试软件和算法&#xff0c;最终将编译好的可执行文件拷贝到Linux板上&#xff08;Rk3288上运行linux系统&#xff09;运行&#xff0c;因此需要安…

【QML】鼠标放在控件上颜色改变的效果实现

最近刚好要用到一个功能&#xff0c;在qml上实现鼠标放上去&#xff0c;控件的颜色改变&#xff0c;鼠标移走&#xff0c;控件颜色恢复。第一反应是这个功能非常简单&#xff0c;但是搞了一会儿都没实现&#xff0c;最后发现MouseArea其实提供了一个很简便的方法来提供使用&…