Android 从LibVLC-android到自编译ijkplayer播放H265 RTSP

news2024/9/25 5:22:57

概述

     ijkplayer: Android/iOS video player based on FFmpeg n3.4, with MediaCodec, VideoToolbox support.
官方的描述就这么简单的一句话,但丝毫都不影响它的强大。

从LibVLC 到 ijkplayer

截止到2023.7.20
LibVLC-Android 最大的问题在与OOM,测试了多个版本后最终选择放弃:
3.1.0/3.2.5/3.3.5/3.5.0/3.6.0/4.0.0-eap1到4.0.0-eap11, 内存随着播放次数增加而递增,到最终出现OOM
4.0.0-eap12: OOM 解决了,setVolume不工作了…

PS
4.0.0-eap12: OOM还和绑定的播放窗口有关, 传入SurfaceView/TextureView是内存泄露问题依然存在;
直到使用了org.videolan.libvlc.util.VLCVideoLayout才得以解决。
另外一个问题是,org.videolan.libvlc.util.VLCVideoLayout在画面切换、覆盖时会出现残留、画面比例失调等问题。

下载了源码编译
vlc-android

export ANDROID_NDK=/home/anson/Android/Sdk/ndk/android-ndk-r14b
export ANDROID_SDK=/home/anson/Android/Sdk
buildsystem/compile.sh -l -a arm 

生成AAR只需要加上 -r 参数即可

OOM问题依旧~ 跟4.0.0-eap12还是有区别


当然也考虑过其他的播放插件如
ExoPlayer, 没有H265,android exoplayer rtsp example
在这里插入图片描述
迁移到了 AndroidX Media3 1.1.0 release.

This is the last planned release of the com.google.android.exoplayer2 artifacts. 
This project is now deprecated. All users should migrate to androidx.media3 (which contains the same ExoPlayer code). 
See the migration guide for more details, including a script to help with the migration

SmarterStreaming ,

PS: 视沃科技-大牛直播移动端
之前没试过,然后下载下来试了下,DEMO APK都跑不了,呵呵,非免费
在这里插入图片描述

GSYVideoPlayer
Android–GSYVideoPlayer框架实现播放视频
怎么说好呢,这是个大合集,EXO, IJK…一样解决不了 RTSP + H265

rtsp-client-android
一些兼容性问题,不出图。

使用ijkplayer

ijkplayer接入方式说明

  1. 从gradle导入的ijkplayer 是不能播放RTSP的
implementation "tv.danmaku.ijk.media:ijkplayer-java:0.8.8"
implementation "tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8"
  1. ijkplayer已经停更好几年了,NDK还是用了 NDK10-NDK14
export ANDROID_NDK=/home/anson/Android/Sdk/ndk/android-ndk-r14b
export ANDROID_SDK=/home/anson/Android/Sdk

ARCH=armv7a

echo ">> INIT "
git checkout -B latest k0.8.8
./init-android.sh
./init-android-openssl.sh

cd android/contrib


echo ">> BUILD OPENSSL"
./compile-openssl.sh clean
./compile-openssl.sh ${ARCH}

echo ">> BUILD FFMPEG"
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh ${ARCH}

echo ">> BUILD IJKPLAYER"
cd ..
./compile-ijk.sh clean
./compile-ijk.sh ${ARCH}

源码的一些修改:

git diff config/module-lite.sh android/contrib/tools/do-compile-ffmpeg.sh
diff --git a/android/contrib/tools/do-compile-ffmpeg.sh b/android/contrib/tools/do-compile-ffmpeg.sh
index d6b3ba63..633b89f6 100755
--- a/android/contrib/tools/do-compile-ffmpeg.sh
+++ b/android/contrib/tools/do-compile-ffmpeg.sh
@@ -267,7 +267,7 @@ FF_CFG_FLAGS="$FF_CFG_FLAGS --prefix=$FF_PREFIX"
 # Advanced options (experts only):
 FF_CFG_FLAGS="$FF_CFG_FLAGS --cross-prefix=${FF_CROSS_PREFIX}-"
 FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-cross-compile"
-FF_CFG_FLAGS="$FF_CFG_FLAGS --target-os=linux"
+FF_CFG_FLAGS="$FF_CFG_FLAGS --target-os=android"
 FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-pic"
 # FF_CFG_FLAGS="$FF_CFG_FLAGS --disable-symver"
 
@@ -292,6 +292,8 @@ case "$FF_BUILD_OPT" in
     ;;
 esac
 
+
+
 #--------------------
 echo ""
 echo "--------------------"
diff --git a/config/module-lite.sh b/config/module-lite.sh
index d5ba3d0f..64c4b05a 100755
--- a/config/module-lite.sh
+++ b/config/module-lite.sh
@@ -42,7 +42,10 @@ export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-swscale"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-postproc"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avfilter"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avresample"
-# export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-pthreads"
+export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-pthreads"
+export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-mediacodec"
+export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-jni"
+
 # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-w32threads"
 # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-os2threads"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-network"
@@ -146,7 +149,8 @@ export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=mmst"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=rtmp*"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtmp"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtmpt"
-export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=rtp"
+export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtp"
+export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtsp"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=sctp"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=srtp"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=subfile"

编译完成后:

JAVA

android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/
├── AbstractMediaPlayer.java
├── AndroidMediaPlayer.java
├── annotations
│   ├── AccessedByNative.java
│   └── CalledByNative.java
├── exceptions
│   └── IjkMediaException.java
├── ffmpeg
│   └── FFmpegApi.java
├── IjkLibLoader.java
├── IjkMediaCodecInfo.java
├── IjkMediaMeta.java
├── IjkMediaPlayer.java
├── IjkTimedText.java
├── IMediaPlayer.java
├── ISurfaceTextureHolder.java
├── ISurfaceTextureHost.java
├── MediaInfo.java
├── MediaPlayerProxy.java
├── misc
│   ├── AndroidMediaFormat.java
│   ├── AndroidTrackInfo.java
│   ├── IAndroidIO.java
│   ├── IjkMediaFormat.java
│   ├── IjkTrackInfo.java
│   ├── IMediaDataSource.java
│   ├── IMediaFormat.java
│   └── ITrackInfo.java
├── pragma
│   ├── DebugLog.java
│   └── Pragma.java
└── TextureMediaPlayer.java

SO 库

android/ijkplayer/ijkplayer-armv7a/src/main/libs/armeabi-v7a/
├── libijkffmpeg.so
├── libijkplayer.so
└── libijksdl.so

这里偷个懒,使用so库即可,build.gradle:

implementation "tv.danmaku.ijk.media:ijkplayer-java:0.8.8"
//这个不要,直接使用编译出来的so库
//implementation "tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8"

一些问题

编译完成后,可以尝试在AndroidStudio中打开ijkplayer的示例项目。AndroidStudio和gradle已经物是人非,使用一些需要修改成一些兼容的版本等配置信息。

android/ijkplayer/build.gradle

--- a/android/ijkplayer/build.gradle
+++ b/android/ijkplayer/build.gradle
@@ -3,9 +3,11 @@
 buildscript {
     repositories {
         jcenter()
+        maven { url 'https://maven.google.com/'}
+        maven { url 'https://maven.aliyun.com/repository/jcenter' }
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.1.3'
+        classpath 'com.android.tools.build:gradle:4.0.1'
 
         classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'
         classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7'
@@ -17,6 +19,8 @@ buildscript {
 allprojects {
     repositories {
         jcenter()
+        maven { url 'https://maven.google.com/'}
+        maven { url 'https://maven.aliyun.com/repository/jcenter' }
     }
 }

android/ijkplayer/gradle/wrapper/gradle-wrapper.properties

@@ -1,6 +1,6 @@
-#Wed Aug 24 16:26:25 CST 2016
+#Wed Jul 19 10:32:59 CST 2023
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip

android/ijkplayer/ijkplayer-example/build.gradle

--- a/android/ijkplayer/ijkplayer-example/build.gradle
+++ b/android/ijkplayer/ijkplayer-example/build.gradle
@@ -16,6 +16,12 @@ android {
         targetSdkVersion rootProject.ext.targetSdkVersion
         versionCode rootProject.ext.versionCode
         versionName rootProject.ext.versionName
+
+        externalNativeBuild{
+            ndk{
+                abiFilters  'armeabi-v7a'
+            }
+        }
     }
     buildTypes {
         release {
@@ -23,36 +29,35 @@ android {
             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
         }
     }
-    productFlavors {
+    /*productFlavors {
         all32 { minSdkVersion 9 }
         all64 { minSdkVersion 21 }
         // armv5 {}
         // armv7a {}
         // arm64 { minSdkVersion 21 }
         // x86 {}
-    }
+    }*/
 }
 
 dependencies {
-    compile fileTree(include: ['*.jar'], dir: 'libs')
-    compile 'com.android.support:appcompat-v7:23.0.1'
-    compile 'com.android.support:preference-v7:23.0.1'
-    compile 'com.android.support:support-annotations:23.0.1'
-
+            }
+        }
     }
     buildTypes {
         release {
@@ -23,36 +29,35 @@ android {
             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
         }
     }
-    productFlavors {
+    /*productFlavors {
         all32 { minSdkVersion 9 }
         all64 { minSdkVersion 21 }
         // armv5 {}
         // armv7a {}
         // arm64 { minSdkVersion 21 }
         // x86 {}
-    }
+    }*/
 }
 
 dependencies {
-    compile fileTree(include: ['*.jar'], dir: 'libs')
-    compile 'com.android.support:appcompat-v7:23.0.1'
-    compile 'com.android.support:preference-v7:23.0.1'
-    compile 'com.android.support:support-annotations:23.0.1'
-
-    compile 'com.squareup:otto:1.3.8'
+    implementation fileTree(include: ['*.jar'], dir: 'libs')
+    implementation 'com.android.support:appcompat-v7:23.0.1'
+    implementation 'com.android.support:preference-v7:23.0.1'
+    implementation 'com.android.support:support-annotations:23.0.1'
 
-    compile project(':ijkplayer-java')
-    compile project(':ijkplayer-exo')
+    implementation 'com.squareup:otto:1.3.8'
 
-    all32Compile project(':ijkplayer-armv5')
-    all32Compile project(':ijkplayer-armv7a')
-    all32Compile project(':ijkplayer-x86')
+    implementation project(':ijkplayer-java')
+    implementation project(':ijkplayer-exo')
 
-    all64Compile project(':ijkplayer-armv5')
-    all64Compile project(':ijkplayer-armv7a')
-    all64Compile project(':ijkplayer-arm64')
-    all64Compile project(':ijkplayer-x86')
-    all64Compile project(':ijkplayer-x86_64')
+    //all32Compile project(':ijkplayer-armv5')
+    implementation project(':ijkplayer-armv7a')
+    //all32Compile project(':ijkplayer-x86')
+    //all64Compile project(':ijkplayer-armv5')
+    //all64Implementation project(':ijkplayer-armv7a')
+    //all64Compile project(':ijkplayer-arm64')
+    //all64Compile project(':ijkplayer-x86')
+    //all64Compile project(':ijkplayer-x86_64')
 
     // compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
     // compile 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.8'

android/ijkplayer/settings.gradle

--- a/android/ijkplayer/settings.gradle
+++ b/android/ijkplayer/settings.gradle
@@ -1,7 +1,7 @@
-include ':ijkplayer-armv5', ':ijkplayer-x86_64'
+//include ':ijkplayer-armv5', ':ijkplayer-x86_64'
 include ':ijkplayer-armv7a'
-include ':ijkplayer-arm64'
-include ':ijkplayer-x86'
+//include ':ijkplayer-arm64'
+//include ':ijkplayer-x86'
 
 include ':ijkplayer-java'
 include ':ijkplayer-exo'
  • cvc-complex-type.2.4.a: Invalid content was found starting with element ‘base-extension’. One of ‘{layoutlib}’ is expected

  • 解决No version of NDK matched the requested version编译报错的问题
    设置NDK路径即可

  • 找不到库:

    defaultConfig {
        applicationId "tv.danmaku.ijk.media.example"
        minSdkVersion 9
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode rootProject.ext.versionCode
        versionName rootProject.ext.versionName

        externalNativeBuild{
            ndk{
                abiFilters  'armeabi-v7a'
            }
        }
    }
  • tv…ia.example W ‘circular_buffer_size’ option was set but it is not supported on this build (pthread support is required)
    FFmpeg在Window上出现’circular_buffer_size’问题解决方法
    最终加上了也没有解决,测试过程中也没有发现有什么问题,放过。

|–/home/anson/work/importProjs/ijkplayer/android/contrib/build/ffmpeg-armv7a/toolchain/bin//arm-linux-androideabi-gcc
ERROR: jni not found

播放 H265 RTSP

  • 如果播放不了,尝试检查下播放器的配置:
 ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-all-videos", 1);
 ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-hevc", 1);
 ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "rtsp_transport", "tcp");

总的来说,ijkplayer 的使用与系统的MediaPlayer很相近。一些优化和延迟可以参考文末的链接。

PS: 若需要频繁切换播放源,特别是一些在线视频,不要吝啬多创建几个ijkplayer的实例,实例的复用不见得可以省多少资源,反而会带来许多意料之外的问题。

参考

  • ijkplayer接入方式说明

  • ijkplayer基于rtsp直播延时的深度优化

  • 移动端开源播放器对比与选型(ExoPlayer/ijkplayer/VLC/GStreamer/SmarterPlayer)

  • How to fix build ffmpeg enable-jni error “jni not found”, support for hard decoding

  • ijkplayer开启rtsp与MJPEG的支持

  • ijkplayer框架的集成( 从开始到优化秒开)

  • ijkplayer播放器剖析(一)从应用层分析至Jni层的流程分析

  • IJKPlayer问题集锦之不定时更新

  • IJKPlayer相关指南

  • ijkplayer 编译与使用

  • IJKPlayer GitHub

  • ijkplayer工程编译FFMPEG+x264+H265解码器支持(iOS环境下)

  • Android 最新(2021-06-10)编译IJKPlayer支持rtsp,延时稳定500ms

  • android exoplayer rtsp example

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

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

相关文章

多线程(JavaEE初阶系列6)

目录 前言: 1.什么是线程池 2.标准库中的线程池 3.实现线程池 结束语: 前言: 在上一节中小编带着大家了解了一下Java标准库中的定时器的使用方式并给大家实现了一下,那么这节中小编将分享一下多线程中的线程池。给大家讲解一…

威胁分析风险评估(TARA)影响和攻击可行性评估参考

在威胁分析风险评估(TARA)过程中,风险等级由对资产安全属性侵害造成后果的影响等级和威胁的可能性两方面综合评估。 备注:以上内容的评估皆是建立在由信息安全问题引起并导致的前提下。 影响等级评估 影响等级说明,影响从安全&a…

k8s-服务发现service和ingress

回到目录 service用于集群内部应用的网络调用,处理东西流量 ingress用于集群外部用户访问内部服务,处理南北流量 一 kube-proxy三种代理模式 kubernetes集群中有三层网络,一类是真实存在的,例如Node Network、Pod Network,提供真…

css position: sticky;实现上下粘性布局,中间区域滚动

sticky主要解决的问题 1、使用absolute和fixed中间区域需要定义高度2、使用absolute和fixed底部需要写padding-bottom 避免列表被遮挡住一部分&#xff08;底部是浮窗的时候&#xff0c;需要动态的现实隐藏&#xff09; <!DOCTYPE html> <html lang"en"&…

从0-1实现简易Raft分布式共识算法

一、Raft前置简介 Raft目前是最著名的分布式共识性算法&#xff0c;被广泛的应用在各种分布式框架、组件中&#xff0c;如Redis、RocketMq、Kafka、Nacos&#xff08;CP&#xff09;等 根据Raft论文&#xff0c;可将Raft拆分为如下4个功能模块&#xff1a; 领导者选举日志同…

蓝桥云课ROS机器人旧版实验报告-04三维建模与仿真

项目名称 实验四 3D建模与仿真 成绩 内容&#xff1a;自定义机器人3D模型&#xff0c;创建一个URDF文件、xacro文件、ROS2[Kinetic/Melodic/Noetic]仿真 实验记录&#xff08;70分&#xff09; 从头开始构建使用 URDF 的可视化机器人模型&#xff1a; 先尝试两个案例&a…

合合信息上会在即:“排队”耗时近两年,能否交出IPO答卷?

撰稿|行星 来源|贝多财经 近日&#xff0c;上海合合信息科技股份有限公司&#xff08;下称“合合信息”&#xff09;在上海证券交易所科创板递交招股书&#xff08;上会稿&#xff09;。据贝多财经了解&#xff0c;合合信息于2021年9月27日递交招股书&#xff0c;将于2023年8…

今日头条面试真题及答案,软件测试工程师面试秘籍

试题1&#xff0e;在浏览器地址栏里输入一个网址&#xff0c;接下来会发生什么&#xff1f; 答案&#xff1a;发生的操作如下。 &#xff08;1&#xff09;浏览器查找该网址的IP地址。 &#xff08;2&#xff09;浏览器根据解析得到的IP地址向Web服务器发送一个HTTP请求。 &am…

CFI技术新探索,struct_san今日登场

一、背景 C/C开发的应用程序&#xff0c;长久以来存在内存破坏类的安全问题。当攻击者掌握了目标程序的漏洞后&#xff0c;就可以开发漏洞利用程序劫持目标程序的控制流。早期的漏洞利用是采用代码注入的方式&#xff0c;通过在缓冲区置入一段代码&#xff08;shellcode&#…

在 Tinkercad 中加快设计的 22 个技巧

在 Tinkercad 中加快设计的 22 个技巧 原文 Everyone knows that Tinkercad is the easiest way to get started in 3D design. Once you get the hang of it, you realize that it’s one of the fastest design tools available. With no software to launch or complex me…

Pytest学习教程_测试报告生成pytest-html(三)

前言 pytest-html 是一个用于生成漂亮的 HTML 测试报告的 pytest 插件。它可以方便地将 pytest 运行的测试结果转换为易于阅读和理解的 HTML 报告&#xff0c;提供了丰富的测试结果展示功能和交互性。 一、安装 # 版本查看命令 pytest版本&#xff1a; pytest --version pyte…

PHP代码审计--理论

提供资料&#xff1a; php 基础 : https://www.runoob.com/php/php-tutorial.html php是什么&#xff1f; PHP 是服务器端脚本语言。 首先在学习PHP前需要对HTML 和CSS有一定的认识 PHP 能做什么&#xff1f; PHP 可以生成动态页面内容PHP 可以创建、打开、读取、写入、关…

InnoDB引擎底层逻辑讲解——架构之磁盘架构

1. System Tablespaces区域 系统表空间是change buffer&#xff08;更改缓冲区&#xff09;的存放区域&#xff0c;这是在8.0之后重新规划的&#xff0c;在5.x版本的时候&#xff0c;系统表空间还会存放innodb的数据字典undolog日志等信息&#xff0c;在8.0之后主要主要存放更…

【程序猿周末如何才能获得充分的休息】

工作以后常常容易感到疲于奔命&#xff0c;即使在周末也没有得到高质量的休息。打工人/学生党如何过周末&#xff1f;你有哪些延长周末和下班时间的好方法吗&#xff1f;你可以选择从以下几个方向谈谈你的想法和观点。 一&#xff1a;周末的时间规划 周末双休 二&#xff1a;提…

springboot 自定义starter项目Unable to read meta-data for class

springboot 自定义starter包&#xff0c;在项目中引用&#xff0c;启动报错。 org.springframework.boot.SpringApplication [SpringApplication.java:843] Application run failed java.lang.IllegalStateException: Unable to read meta-data for class com.hxg.mail.spring…

找好听的配乐、BGM就上这6个网站,免费商用。

推荐几个音乐素材网站给你&#xff0c;各种类似、风格的都有&#xff0c;而且免费下载&#xff0c;还可以商用&#xff0c;建议收藏起来~ 菜鸟图库 https://www.sucai999.com/audio.html?vNTYxMjky 站内有上千首音效素材&#xff0c;网络流行的音效素材这里都能找到&#xf…

一起学算法(双指针篇)

概念&#xff1a; 通过两个指针&#xff0c;不断的调整区间&#xff0c;从而求出问题最优解的算法就叫“尺取法”&#xff0c;由于利用的是两个双指针&#xff0c;所以也叫作“双指针”算法&#xff0c;这里的“尺”的含义&#xff0c;主要是因为这类问题&#xff0c;最终要求解…

刷题笔记 day2

力扣 1089 复写零 思路&#xff1a;双指针 第一步&#xff1a;利用指针 cur 去记录最后一位要复写的数 &#xff0c; 利用指针 dest 指向最后一位数所要复写的位置&#xff1b; 实现过程&#xff1a;最开始 cur 指向0&#xff0c;dest 指向 -1 &#xff0c; 当arr[cur] ! …

高并发与性能优化的神奇之旅

作为公司的架构师或者程序员&#xff0c;你是否曾经为公司的系统在面对高并发和性能瓶颈时感到手足无措或者焦头烂额呢&#xff1f;笔者在出道那会为此是吃尽了苦头的&#xff0c;不过也得感谢这段苦&#xff0c;让笔者从头到尾去探索&#xff0c;找寻解决之法。 目录 第一站&…

深入理解设计模式之模板方法模式

深入理解设计模式之模板方法模式 什么是模板方法模式&#xff1f; 模板方法模式是一种行为型设计模式&#xff0c;它定义了一个算法的骨架&#xff0c;将一些步骤的具体实现延迟到子类中。模板方法模式通过将算法的通用部分抽象出来&#xff0c;以模板方法的形式提供给子类&am…