J2C_CountDownLatch_2_信号量_比较

本文对比了Java中的CountDownLatch(门栓)与C语言中的信号量(semaphore)在多线程/多进程间的应用。通过两个示例,一是Java中使用CountDownLatch协调两个线程的工作流程;二是C语言中利用信号量实现生产者-消费者模型。

前言:Java的门栓即闭锁与C的信号量

    Java                                                                                         C

//1变成0,门就开了                                          sem_wait(&produce_sem);  //produce_sem==0,阻塞

//调用一次countDown()自减1                           sem_post(&custom_sem); //custom_sem++,通知消费者消费

//并且自身线程也可以向下执行                         sem_wait(&custom_sem); //custom_sem==0,阻塞

CountDownLatch                                              sem_post(&produce_sem); //produce_sem++

 

/**************************************Java********************************/
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class CountDownLatch_Value {
    volatile List lists=new ArrayList();
    public void add(Object o){
	lists.add(o);
    }
    public int size(){
	return lists.size();
    }

    public static void main(String[] args) {
	final CountDownLatch_Value c=new CountDownLatch_Value();
	//闭锁,即信号量,即门栓
	//效率最高,并发最好
	final CountDownLatch latch=new CountDownLatch(1); //1变成0,门就开了
		
	/*
         *  线程1
         */
	new Thread(new Runnable() {
	    public void run() {
	        System.out.println("t1启动");
		for(int i=0;i<10;i++){
		    c.add(new Object());
		    System.out.println("add"+i);
		    if(c.size()==5){
                 //调用一次countDown()自减1,打开门栓,让t2得以执行,并且自身线程也可以向下执行
		         latch.countDown();	
		    }
		    try {
			Thread.sleep(1000);
		    } catch (InterruptedException e) {
			e.printStackTrace();
		    }
		}
	    }
	},"t1").start();
		

	/*
         *  线程2
         */
	new Thread(new Runnable() {
	    public void run() {
		System.out.println("t2启动"); //先启动起来
		if(c.size()!=5){
		    try{
		        latch.await(); //门栓等待,不需要锁定任何对象,线程阻塞在这里
		        //latch.await(5000,TimeUnit.MILLISECONDS)) //也可以指定等待时间
		    }catch(InterruptedException e){
		        e.printStackTrace();
		    }
	        }
	        System.out.println("t2结束");
	    }
	},"t2").start();
	
	try {
            Thread.sleep(1000);
	} catch (InterruptedException e) {
	    e.printStackTrace();
	}		
    }
}


/*******************************C***************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>  
#include <semaphore.h>

sem_t produce_sem; //生产者与消费者信号量
sem_t custom_sem;

typedef struct node  
{
   int data;  //数据域
   struct node* next; //指针域
}Node;

Node* head=NULL;

/*
 *生产者
 */
void* producer(void* arg)
{
    while(1)
    {
	sem_wait(&produce_sem); //produce_sem==0,阻塞//produce_sem--
	Node* node = (Node*)malloc(sizeof(Node)); //malloc返回值是void*,强制转换(Node*)
	node->data = rand()%1000;  //(0-999)
	node->next = head;
	head=node; 	
	printf("======生产者:%lu,%d\n",pthread_self(),node->data);
	sem_post(&custom_sem); //custom_sem++,通知消费者消费//释放资源

	sleep(rand()%5);  //休息5秒以内,取余数
    }
    return NULL;
}

/*
 *    消费者
 */
void* customer(void* arg)
{
    while(1)
    {        
        //custom_sem==0,阻塞//等待生产者操作custom_sem++,然后解除阻塞开始执行
        sem_wait(&custom_sem); 
	Node* del=head;  //定义一个变量
	head=head->next;  //头指针向下一个节点移动
	printf("--------消费者:%lu,%d\n",pthread_self(),del->data);
	free(del);	
	sem_post(&produce_sem); //produce_sem++//释放资源//资源还给生产者

	sleep(rand()%5);
    }
    return NULL;
}


int main(int argc,const char* argv[]) //在main函数中的方法属于父线程
{
   
    //0,代表线程同步。1,代表进程同步//4,代表最多有四个线程可以同时操作共享数据
    sem_init(&produce_sem,0,4); 
    sem_init(&custom_sem,0,0);  //初始化消费者线程信号量

    pthread_t thid[2]; 
    pthread_create(&thid[0],NULL,producer,NULL); //创建线程
    pthread_create(&thid[1],NULL,customer,NULL);  
  
    int i=0;
    for(i=0;i<2;++i)    
    {
	pthread_join(thid[i],NULL); //阻塞等待回收子线程的pcb
    }

    sem_destroy(&produce_sem);  //3---销毁信号量
    sem_destroy(&custom_sem);

    return 0;
    
}

 

mark: 学习笔记

不要定义已经有的方法和接口,而是使用他们,不需要定义protected Integer doInBackground(Void... voids) {,这是稍后的任务,package com.kotei.overseas.navi.update; import static com.kotei.overseas.navi.security.DecryptUtil.dataVerification; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.AsyncTask; import android.os.Handler; import android.os.Looper; import android.util.Log; import java.util.concurrent.Future; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicLong; import com.here.sdk.core.engine.SDKNativeEngine; import com.kotei.overseas.navi.business.data.MapDataController; import com.kotei.overseas.navi.security.DecryptUtil; import com.kotei.overseas.navi.security.DfCert; import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; import java.util.stream.Stream; /** * USB离线更新系统 */ public class USBOfflineUpdater { // 日志标签 private static final String TAG = "USBOfflineUpdater"; // 操作成功状态码 public static final int SUCCESS = 0; // 错误状态码 public static final int ERROR_NO_USB = 1; // 未检测到USB设备 public static final int ERROR_NO_UPDATE_PACKAGE = 2; // 未找到升级包 public static final int ERROR_BATTERY_LOW = 3; // 电池电量不足 public static final int ERROR_STORAGE_INSUFFICIENT = 4; // 存储空间不足 public static final int ERROR_UPDATE_IN_PROGRESS = 5; // 升级任务冲突 public static final int ERROR_COPY_FAILED = 6; // 文件复制失败 public static final int ERROR_EXTRACT_FAILED = 7; // 解压失败 public static final int ERROR_USER_CANCELED = 8; // 用户取消 public static final int ERROR_UNEXPECTED = 9; // 未预期异常 public static final int ERROR_USB_REMOVED = 10; // USB设备移除 public static final int ERROR_VEHICLE_SHIFTED = 11; // 非P档状态 public static final int ERROR_BATTERY_TOO_LOW = 12; // 电池极低 public static final int ERROR_FILE_VERIFY_FAILED = 13; // 文件校验失败 public static final int ERROR_DECRYPT_OR_SIGN_FAILED = 14; // 解密/验签失败 // 更新阶段常量 private static final int PHASE_IDLE = 0; // 空闲 private static final int PHASE_DETECTING = 1; // 设备检测 private static final int PHASE_CHECKING = 2; // 校验 private static final int PHASE_BACKUP = 3; // 备份 private static final int PHASE_COPYING = 4; // 复制 private static final int PHASE_EXTRACTING = 5; // 解压 private static final int PHASE_CLEANUP = 6; // 清理 private static final int PHASE_ROLLBACK = 7; // 回滚 // 进度权重分配 private static final float BACKUP_WEIGHT = 0.1f; // 备份阶段权重 private static final float PACKAGE_COPY_WEIGHT = 0.29f; // 拷贝阶段权重 private static final float PACKAGE_VERIFY_WEIGHT = 0.31f; // 验签阶段权重 private static final float PACKAGE_EXTRACT_WEIGHT = 0.29f; // 解压阶段权重 private static final float VERIFICATION_WEIGHT = 0.01f; // 校验阶段权重 // 文件名正则表达式 private static final String FILE_NAME_PATTERN = "^KVM_Navi_EU_" + "(?<version>\\d{1,3})" // 版本号(1-3位数字) + "_" + "(?<serial>\\d{1,2})" // 1-2位序列号 + "(\\.\\w+)?$"; // 可选扩展名 // 当前进度值(0~1) private float mProgress = 0; // 单例实例 private static USBOfflineUpdater instance; // 上下文对象 private final Context context; // 当前更新任务 private UpdateTask currentTask; // 更新监听器 private UpdateListener updateListener; // 原生引擎接口 private SDKNativeEngine sdkNativeEngine; // 地图数据控制器 private MapDataController mapDataController; // USB根目录 private File usbRoot; // 缓存目录(备份文件) private File cacheDir; // 存储目录(升级目标) private File storageDir; // 暂停状态标志 public boolean isPaused = false; // 取消状态标志(volatile保证线程可见性) public volatile boolean isCancelled = false; // 当前阶段(原子操作) public final AtomicInteger currentPhase = new AtomicInteger(PHASE_IDLE); // 最后错误信息 private String lastErrorMessage = ""; // 最低电量阈值(安全) private static final int MIN_BATTERY_LEVEL = 30; // 最低电量阈值(严重) private static final int MIN_BATTERY_LEVEL_CRITICAL = 15; // 总升级包大小 private long totalUpdateSize = 0; // 当前升级包大小 private long UpdateSize = 0; // 已拷贝字节数(原子操作) private final AtomicLong currentCopiedBytes = new AtomicLong(0); // 已验签字节数(原子操作) private final AtomicLong currentVerifiedBytes = new AtomicLong(0); // 已解压字节数(原子操作) private final AtomicLong currentExtractedBytes = new AtomicLong(0); // 备份数据大小 private long backupSize = 0; // 总升级包数量 private int totalPackageCount = 0; // 回滚状态 public boolean isRollingBack = false; // 回滚总大小 private long rollbackTotalSize = 0; // 回滚已处理大小 private long rollbackProcessedSize = 0; // 包级锁对象 private final Object packageLock = new Object(); // 更新成功标志(volatile保证线程可见性) private volatile boolean updateSuccess = true; // 下一个待处理包索引 private int nextPackageIndex = 0; // 主线程Handler private Handler mainHandler = new Handler(Looper.getMainLooper()); // 包处理完成信号量 private volatile CountDownLatch allPackagesLatch; // 更新线程池 private volatile ExecutorService updateExecutor; // 总包大小(原子操作) private final AtomicLong totalPackageSize = new AtomicLong(0); // 每个包的最大进度(百分比) private static final double MAX_PACKAGE_PROGRESS = 17.8; // 总进度中包处理部分(百分比) private static final double TOTAL_PACKAGE_PROGRESS = 89.0; // 包进度映射(线程安全) private final Map<String, Double> packageProgressMap = new ConcurrentHashMap<>(); // 包总大小映射(线程安全) private final Map<String, Long> packageTotalSizeMap = new ConcurrentHashMap<>(); // 包阶段映射(线程安全) private final Map<String, Integer> packageStageMap = new ConcurrentHashMap<>(); // 阶段标识 private static final int STAGE_COPY = 0; // 拷贝阶段 private static final int STAGE_VERIFY = 1; // 验签阶段 private static final int STAGE_EXTRACT_ONLY = 2; // 仅解压阶段 // 解密验签阶段 private static final int PHASE_DECRYPT_VERIFY = 4; // 仅解压阶段 private static final int PHASE_EXTRACTING_ONLY = 5; private CountDownLatch verifyLatch; // 解密验签阶段的同步信号量 // 在 USBOfflineUpdater 类中添加缺失的变量 private CountDownLatch backupLatch = new CountDownLatch(1); // 备份任务同步信号量 //-----------------------------zwxend---------------- // USB监听器 private final BroadcastReceiver usbReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (Intent.ACTION_MEDIA_MOUNTED.equals(action)) { File usbPath = new File(intent.getData().getPath()); if (usbPath.exists() && usbPath.canRead()) { usbRoot = usbPath; Log.i(TAG, "USB mounted: " + usbRoot.getAbsolutePath()); } } else if (Intent.ACTION_MEDIA_EJECT.equals(action) || Intent.ACTION_MEDIA_UNMOUNTED.equals(action)) { if (currentTask != null && currentPhase.get() > PHASE_CHECKING) { cancelUpdate(ERROR_USB_REMOVED, "USB设备被移除"); } usbRoot = null; Log.e(TAG, "USB removed"); } } }; // // 车辆状态监听器(模拟) private final BroadcastReceiver vehicleReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if ("com.example.ACTION_SHIFT_CHANGE".equals(intent.getAction())) { String shift = intent.getStringExtra("shift"); if (!"P".equals(shift) && currentPhase.get() > PHASE_CHECKING) { // cancelUpdate(ERROR_VEHICLE_SHIFTED, "车辆已退出P挡"); } } } }; // 单例模式 public static synchronized USBOfflineUpdater getInstance(Context context) { if (instance == null) { instance = new USBOfflineUpdater(context); } return instance; } public static synchronized USBOfflineUpdater getInstance() { return instance; } private USBOfflineUpdater(Context context) { this.context = context.getApplicationContext(); // 初始化SDK sdkNativeEngine = SDKNativeEngine.getSharedInstance(); mapDataController = MapDataController.getInstance(); try { DfCert.getInstance().getService(); } catch (Exception e) { Log.e(TAG, "Exception:" + e.toString()); } // 初始化目录(默认值) cacheDir = this.context.getCacheDir(); storageDir = new File(sdkNativeEngine.getOptions().persistentMapStoragePath); // 注册USB监听器 IntentFilter usbFilter = new IntentFilter(); usbFilter.addAction(Intent.ACTION_MEDIA_MOUNTED); usbFilter.addAction(Intent.ACTION_MEDIA_EJECT); usbFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED); usbFilter.addDataScheme("file"); context.registerReceiver(usbReceiver, usbFilter); // 注册车辆状态监听器(模拟) IntentFilter vehicleFilter = new IntentFilter("com.example.ACTION_SHIFT_CHANGE"); context.registerReceiver(vehicleReceiver, vehicleFilter); //清除数据存储目录下的预留数据 removeLegacy(); } public void initialization(UpdateListener listener) { isRollingBack = true; this.updateListener = listener; Thread USBOfflineUpdaterInitialization = new Thread(new Runnable() { @Override public void run() { // 启动时检查恢复 checkRecoveryOnStartup(); } }); USBOfflineUpdaterInitialization.setName("USBOfflineUpdaterInitialization"); USBOfflineUpdaterInitialization.start(); } // 动态设置目录 public void setDirectories(File usbRoot, File cacheDir, File storageDir) { if (usbRoot != null) { this.usbRoot = usbRoot; } if (cacheDir != null) { this.cacheDir = cacheDir; } if (storageDir != null) { this.storageDir = storageDir; } } /** * 检测升级包 * * @return 状态码 (SUCCESS 或错误码) */ public int detectUpdatePackages() { // 1. 检测USB是否插入 if (usbRoot == null || !usbRoot.exists() || !usbRoot.isDirectory()) { return ERROR_NO_USB; } File[] tempPackages = usbRoot.listFiles(); // 2. 查找升级包 (命名格式: update_v{版本号}_{日期}.zip) File[] packages = usbRoot.listFiles(file -> file.isFile() && file.getName().matches(FILE_NAME_PATTERN) ); return (packages != null && packages.length > 0) ? SUCCESS : ERROR_NO_UPDATE_PACKAGE; } /** * 环境检测 * * @return 状态码 (SUCCESS 或错误码) */ public int checkEnvironment() { // 1. 检测电量 int batteryLevel = PowerUtils.getBatteryLevel(context); if (batteryLevel < MIN_BATTERY_LEVEL) { return batteryLevel < MIN_BATTERY_LEVEL_CRITICAL ? ERROR_BATTERY_TOO_LOW : ERROR_BATTERY_LOW; } // 2. 检测缓存空间 (需大于15GB) long requiredSpace = 15L * 1024 * 1024 * 1024; // 15GB long availableSpace = StorageUtils.getAvailableSpace(cacheDir); if (availableSpace < requiredSpace) { Log.e(TAG, "缓存空间剩余:【" + availableSpace + "】"); return ERROR_STORAGE_INSUFFICIENT; } return SUCCESS; } /** * 判读是否正在进行离线更新 */ public boolean isOfflineUpdate() { return currentTask != null && !currentTask.isCancelled(); } /** * 开始更新 */ public void startUpdate(UpdateListener listener) { int result = checkEnvironment(); if (result != SUCCESS) { notifyListener(result, "环境检测不合格"); return; } if (isOfflineUpdate()) { notifyListener(ERROR_UPDATE_IN_PROGRESS, "已有更新任务正在进行"); return; } if (isRollingBack) { notifyListener(ERROR_UPDATE_IN_PROGRESS, "正在进行数据回滚"); return; } Log.i(TAG, "检测到更新任务触发,开始进行地图更新"); notifyProgress("开始进行更新"); // 计算总工作量(新增) calculateTotalWorkload(); this.updateListener = listener; currentTask = new UpdateTask(); currentTask.execute(); } // 计算总工作量(新增) private void calculateTotalWorkload() { totalUpdateSize = 0; File[] packages = getUpdatePackages(); totalPackageCount = packages != null ? packages.length : 0; if (packages != null) { for (File pkg : packages) { totalUpdateSize += pkg.length(); } } backupSize = estimateBackupSize(); Log.i(TAG, "总工作量计算: 升级包数量=" + totalPackageCount + ", 升级包大小=" + formatSize(totalUpdateSize) + ", 备份大小=" + formatSize(backupSize)); } // 估算备份大小方法(避免返回0导致除0错误) private long estimateBackupSize() { long storageSize = FileUtilszwx.getDirectorySize(storageDir); long size = (long) (storageSize * 1.2); return size > 0 ? size : 1; // 确保不为0 } // 获取更新包(新增) private File[] getUpdatePackages() { if (usbRoot == null) return new File[0]; return usbRoot.listFiles(file -> file.isFile() && file.getName().matches(FILE_NAME_PATTERN) ); } // 格式化文件大小(新增) public static String formatSize(long size) { if (size < 1024) return size + "B"; else if (size < 1024 * 1024) return String.format("%.1fKB", size / 1024.0); else if (size < 1024 * 1024 * 1024) return String.format("%.1fMB", size / (1024.0 * 1024)); else return String.format("%.1fGB", size / (1024.0 * 1024 * 1024)); } /** * 暂停更新 */ public void pauseUpdate() { isPaused = true; notifyProgress("更新已暂停"); } /** * 恢复更新 */ public void resumeUpdate() { isPaused = false; notifyProgress("更新已恢复"); } /** * 取消更新 */ public void cancelUpdate() { cancelUpdate(ERROR_USER_CANCELED, "用户取消更新"); } private void cancelUpdate(int errorCode, String message) { isCancelled = true; lastErrorMessage = message; notifyListener(errorCode, message); } // 进度通知 private void notifyProgress(String message) { new Handler(Looper.getMainLooper()).post(() -> { if (updateListener != null) { // 计算当前总进度(修改) float progress = calculateOverallProgress(); updateListener.onProgress(currentPhase.get(), progress, message); } }); } private float calculateOverallProgress() { if (isRollingBack) { // 回滚阶段:直接计算回滚进度 if (rollbackTotalSize > 0) { mProgress = 99; return mProgress; } return 0; } if (totalPackageCount == 0 && currentPhase.get() != PHASE_ROLLBACK) return 0; // 每个包的总权重(拷贝+验签+解压) // float packageTotalWeight = PACKAGE_COPY_WEIGHT + // PACKAGE_VERIFY_WEIGHT + // PACKAGE_EXTRACT_WEIGHT; float packageTotalWeight = PACKAGE_COPY_WEIGHT + PACKAGE_VERIFY_WEIGHT; // 不再包含解压 //再次确认totalPackageCount是否等于0 if (totalPackageCount == 0) { throw new IllegalStateException("totalPackageCount should not be 0 here!"); } // 每个包的阶段权重 float packageCopyWeight = PACKAGE_COPY_WEIGHT / totalPackageCount; float packageVerifyWeight = PACKAGE_VERIFY_WEIGHT / totalPackageCount; float packageExtractWeight = PACKAGE_EXTRACT_WEIGHT / totalPackageCount; // 当前处理的升级包索引 int currentPackageIndex = 0; switch (currentPhase.get()) { case PHASE_BACKUP: if (backupSize > 0) { mProgress = BACKUP_WEIGHT * (currentCopiedBytes.get() / (float) backupSize); } else { mProgress = BACKUP_WEIGHT; } if (mProgress > BACKUP_WEIGHT) { mProgress = BACKUP_WEIGHT; } break; case PHASE_COPYING: // 基础:备份 + 已完成包的完整进度 float copyBase = BACKUP_WEIGHT + (packageTotalWeight * currentPackageIndex) / totalPackageCount; // 增量:当前包拷贝进度 float copyProgress = currentCopiedBytes.get() / (float) UpdateSize; mProgress = copyBase + packageCopyWeight * copyProgress; break; case PHASE_CHECKING: // 基础:备份 + 已完成包的完整进度 + 当前包拷贝完成 float verifyBase = BACKUP_WEIGHT + (packageTotalWeight * currentPackageIndex) / totalPackageCount + packageCopyWeight; // 增量:当前包验签进度 float verifyProgress = currentVerifiedBytes.get() / (float) UpdateSize; mProgress = verifyBase + packageVerifyWeight * verifyProgress; break; case PHASE_EXTRACTING: // 修复:添加当前包验签完成 float extractBase = BACKUP_WEIGHT + (packageTotalWeight * currentPackageIndex) / totalPackageCount + packageCopyWeight + packageVerifyWeight; // 添加这行 // 增量:当前包解压进度 float extractProgress = currentExtractedBytes.get() / (float) UpdateSize; mProgress = extractBase + packageExtractWeight * extractProgress; break; case PHASE_DETECTING: mProgress = BACKUP_WEIGHT + packageTotalWeight + VERIFICATION_WEIGHT * (currentVerifiedBytes.get() / (float) totalUpdateSize); break; case PHASE_CLEANUP: case PHASE_ROLLBACK: mProgress = 0.99f; break; } return Math.min(Math.round(mProgress * 10000) / 100.00f, 100.00f); } // 结果通知 private void notifyListener(int resultCode, String message) { new Handler(Looper.getMainLooper()).post(() -> { if (updateListener != null) { updateListener.onResult(resultCode, message); } }); } // 获取当前进度百分比 private int getCurrentProgress() { // 此处可添加子任务进度计算 return (int) mProgress; } // =============================== 核心更新逻辑 =============================== private class UpdateTask extends AsyncTask<Void, Void, Integer> { private File backupFile; private File[] updatePackages; @Override protected void onPreExecute() { currentPhase.set(PHASE_DETECTING); isCancelled = false; isPaused = false; currentCopiedBytes.set(0); currentExtractedBytes.set(0); mProgress = 0; // 重置进度为0 } @Override protected Integer doInBackground(Void... voids) { try { // 阶段1: 备份数据 currentPhase.set(PHASE_BACKUP); notifyProgress("开始备份数据..."); // 创建备份线程池(T1) ExecutorService backupExecutor = Executors.newSingleThreadExecutor(); Future<Boolean> backupFuture = backupExecutor.submit(() -> performBackup()); // 阶段2a: 拷贝 + 解密验签(TS2a) ExecutorService serialCopyExecutor = Executors.newSingleThreadExecutor(); ExecutorService parallelVerifyExecutor = Executors.newFixedThreadPool(3); // 阶段2b: 解压(T2b) ExecutorService serialExtractExecutor = Executors.newSingleThreadExecutor(); // 等待备份完成 backupLatch.await(); // 等待 T1 完成 boolean backupSuccess = backupFuture.get(); if (!backupSuccess || isCancelled()) { return ERROR_UNEXPECTED; } // 并行处理拷贝 + 解密验签(TS2a) processUpdatePackagesInParallel(updatePackages, serialCopyExecutor, parallelVerifyExecutor); // 等待 TS2a 完成 verifyLatch.await(); // 等待所有解密验签完成 // 阶段2b: 解压(T2b) for (File packageFile : updatePackages) { if (isCancelled()) break; serialExtractExecutor.submit(new SerialExtractTask(packageFile)); } // 关闭解压线程池 serialExtractExecutor.shutdown(); if (!serialExtractExecutor.awaitTermination(1, TimeUnit.HOURS)) { return ERROR_UNEXPECTED; } // 校验 if (!mapDataController.checkInstallationStatus()) { return ERROR_FILE_VERIFY_FAILED; } return SUCCESS; } catch (Exception e) { return ERROR_UNEXPECTED; } } @Override protected void onPostExecute(Integer resultCode) { if (resultCode == SUCCESS) { notifyListener(SUCCESS, "更新成功,请重启车机"); currentPhase.set(PHASE_IDLE); currentTask = null; } else { // 只有备份完成时才进行回滚(场景2) if (backupFile != null && backupFile.exists()) { // 场景2:进入回滚流程 isRollingBack = true; currentPhase.set(PHASE_ROLLBACK); // 先发送回滚进度通知(99%) notifyProgress("更新失败,正在回滚数据..."); // 保存错误消息,因为回滚完成后还需要使用 final String errorMessage = lastErrorMessage; // 启动回滚线程 new Thread(new Runnable() { @Override public void run() { try { // 执行回滚 performRollback(backupFile); } finally { // 回滚完成后删除备份 // backupFile.delete(); if (backupFile.exists() && !backupFile.delete()) { Log.w(TAG, "删除备份文件失败: " + backupFile.getAbsolutePath()); } if (!isCancelled) { // 回滚完成后发送最终结果 notifyListener(resultCode, getErrorMessage(resultCode)); } // 重置状态 currentPhase.set(PHASE_IDLE); currentTask = null; isRollingBack = false; } } }).start(); } else { // 场景1:没有备份文件,直接报告错误 notifyListener(resultCode, lastErrorMessage); currentPhase.set(PHASE_IDLE); currentTask = null; } } } } // ================== 启动时恢复检查 ================== private void checkRecoveryOnStartup() { File backupFile = findLatestBackupFile(); // 存在备份文件说明上次更新中断 if (backupFile != null && backupFile.exists()) { long fileSize = backupFile.length(); long expectedSize = estimateBackupSize(); // 场景3:备份未完成(文件大小小于预期大小的90%) if (fileSize < expectedSize * 0.9) { isRollingBack = true; Log.i(TAG, "检测到未完成的备份,删除: " + backupFile.getName()); // backupFile.delete(); if (backupFile.exists() && !backupFile.delete()) { Log.w(TAG, "删除备份文件失败: " + backupFile.getAbsolutePath()); } return; } else { // 场景4:备份已完成,启动回滚 Log.i(TAG, "检测到完整的备份,开始回滚: " + backupFile.getName()); currentPhase.set(PHASE_ROLLBACK); notifyProgress("检测到未完成更新,正在恢复数据..."); // 执行回滚 performRollback(backupFile); // 删除备份文件 // backupFile.delete(); if (backupFile.exists() && !backupFile.delete()) { Log.w(TAG, "删除备份文件失败: " + backupFile.getAbsolutePath()); } notifyProgress("数据恢复完成"); } } isRollingBack = false; this.updateListener = null; } private void checkStoragePerformance() { long writeSpeed = StorageUtils.measureWriteSpeed(storageDir); Log.d(TAG, "存储写入速度: " + formatSize(writeSpeed) + "/s"); if (writeSpeed < 50 * 1024 * 1024) { // 低于 50MB/s Log.w(TAG, "检测到低速存储设备,还原操作可能较慢"); } } // 新增回滚方法 private void performRollback(File backupFile) { try { // 1. 设置回滚进度为99% rollbackProcessedSize = backupFile.length() * 99 / 100; notifyProgress("开始恢复备份..."); // 2. 删除更新后的数据 FileUtilszwx.deleteRecursive(storageDir); if (!storageDir.mkdirs()) { Log.w(TAG, "创建存储目录失败"); } // 3. 恢复备份 rollbackTotalSize = backupFile.length(); rollbackProcessedSize = 0; boolean restoreSuccess = FileUtilszwx.extractZipWithProgress( backupFile, storageDir, (extracted, total) -> { rollbackProcessedSize = extracted; notifyProgress(String.format("恢复备份 %s: %s/%s", backupFile.getName(), formatSize(extracted), formatSize(total))); } ); if (!restoreSuccess) { Log.e(TAG, "备份恢复失败"); } } catch (Exception e) { Log.e(TAG, "回滚过程中发生错误", e); } } private File findLatestBackupFile() { File[] backups = cacheDir.listFiles(file -> file.isFile() && file.getName().startsWith("backup.zip") ); if (backups == null || backups.length == 0) { return null; } return backups[0]; } // 释放资源 public void release() { try { context.unregisterReceiver(usbReceiver); context.unregisterReceiver(vehicleReceiver); } catch (Exception e) { Log.w(TAG, "释放资源时出错", e); } } // ================== 接口定义 ================== public interface UpdateListener { void onProgress(int phase, float progress, String message); void onResult(int resultCode, String message); } public interface ProgressCallback { void onProgress(long progress, long total) throws InterruptedException; } public File getUsbRoot() { return usbRoot; } public File getCacheDir() { return cacheDir; } public File getStorageDir() { return storageDir; } public String getErrorMessage(int code) { return switch (code) { case ERROR_NO_USB -> "未检测到USB设备,请检查连接状态或更换接口"; case ERROR_NO_UPDATE_PACKAGE -> "升级包文件缺失,请确认存储路径"; case ERROR_BATTERY_LOW -> "电池电量不足(需≥20%)"; case ERROR_STORAGE_INSUFFICIENT -> "存储空间不足(需预留500MB以上)"; case ERROR_UPDATE_IN_PROGRESS -> "系统正在执行其他升级任务"; case ERROR_COPY_FAILED -> "文件复制失败,请检查存储权限"; case ERROR_EXTRACT_FAILED -> "升级包解压失败(可能文件损坏)"; case ERROR_USER_CANCELED -> "用户已取消升级操作"; case ERROR_UNEXPECTED -> "发生未预期的系统异常"; case ERROR_USB_REMOVED -> "升级过程中USB设备被移除"; case ERROR_VEHICLE_SHIFTED -> "请将车辆档位切换至P档"; case ERROR_BATTERY_TOO_LOW -> "电池电量极低(需≥10%)"; case ERROR_FILE_VERIFY_FAILED -> "文件校验失败(MD5/SHA256不匹配)"; case ERROR_DECRYPT_OR_SIGN_FAILED -> "文件解密/验签失败"; default -> "未知错误导致更新失败"; }; } void removeLegacy() { if (storageDir == null || !storageDir.exists() || !storageDir.isDirectory()) { return; } Pattern pattern = Pattern.compile(FILE_NAME_PATTERN); File[] files = storageDir.listFiles(); if (files == null) return; for (File file : files) { if (file.isFile() && pattern.matcher(file.getName()).matches()) { // 删除匹配的文件 try { Files.deleteIfExists(file.toPath()); } catch (IOException | SecurityException e) { // 处理异常(记录日志等) } } } // 删除sign文件夹(如果存在) Path signDir = Paths.get(storageDir.getAbsolutePath(), "sign"); if (Files.exists(signDir)) { try { // 递归删除整个目录 deleteDirectoryRecursively(signDir); } catch (IOException | SecurityException e) { // 处理异常 } } } private void deleteDirectoryRecursively(Path path) throws IOException { if (Files.isDirectory(path)) { // 使用 try-with-resources 确保 Stream 关闭 try (Stream<Path> children = Files.list(path)) { children.forEach(child -> { try { deleteDirectoryRecursively(child); } catch (IOException e) { // 处理子项删除异常 throw new UncheckedIOException(e); // 转换为 RuntimeException 以便在 Stream 中抛出 } }); } catch (UncheckedIOException e) { // 重新抛出原始 IOException throw e.getCause(); } } // 删除空目录或文件 Files.deleteIfExists(path); } //-----------------------------------多线程------------------------ /** * 并行更新管道,用于并发处理多个升级包 */ /** * 并行更新管道,用于并发处理多个升级包 */ /** * 并行处理升级包 */ private boolean performBackup() { try { File backupFile = new File(cacheDir, "backup.zip"); if (backupFile.exists() && !backupFile.delete()) { Log.w(TAG, "删除旧备份文件失败"); } backupSize = estimateBackupSize(); Log.i(TAG, "需要备份的数据大小: [" + formatSize(backupSize) + "]"); try { boolean result = FileUtilszwx.compressDirectoryWithProgress( storageDir, backupFile, (copied, total) -> { currentCopiedBytes.set(copied); notifyProgress("备份数据: " + USBOfflineUpdater.formatSize(copied) + "/" + USBOfflineUpdater.formatSize(total)); if (isCancelled) { throw new RuntimeException(new InterruptedException("用户取消备份")); } } ); return result; } catch (RuntimeException e) { if (e.getCause() instanceof InterruptedException) { Log.d(TAG, "备份任务被用户取消"); return false; } else { Log.e(TAG, "未知异常", e); throw e; } } } catch (Exception e) { Log.e(TAG, "备份失败", e); return false; } finally { backupLatch.countDown(); // 无论成功与否,触发备份完成信号 } } private void updateProgress(String format, String packageName, long processed, long total) { String message = String.format(format, packageName, formatSize(processed), formatSize(total)); mainHandler.post(() -> notifyProgress(message)); } private void processUpdatePackagesInParallel( File[] packages, ExecutorService serialCopyExecutor, ExecutorService parallelVerifyExecutor) { if (packages == null || packages.length == 0) { notifyListener(SUCCESS, "无升级包"); return; } // 初始化每个包的进度信息 for (File packageFile : packages) { packageTotalSizeMap.put(packageFile.getName(), packageFile.length()); packageProgressMap.put(packageFile.getName(), 0.0); packageStageMap.put(packageFile.getName(), STAGE_COPY); } allPackagesLatch = new CountDownLatch(packages.length); verifyLatch = new CountDownLatch(packages.length); // 并行提交拷贝任务(使用线程池) for (File packageFile : packages) { if (isCancelled) break; File destFile = new File(cacheDir, packageFile.getName()); // 提交到线程池并行执行 serialCopyExecutor.submit(() -> { try { // 执行拷贝逻辑(示例) copyPackageFile(packageFile, destFile); // 提交解密验签任务到线程池 parallelVerifyExecutor.submit(new PostCopyProcessingTask(packageFile, destFile, allPackagesLatch, verifyLatch)); } catch (Exception e) { Log.e(TAG, "拷贝任务失败", e); allPackagesLatch.countDown(); verifyLatch.countDown(); } }); } // 关闭线程池后触发 verifyLatch serialCopyExecutor.shutdown(); parallelVerifyExecutor.shutdown(); new Thread(() -> { try { serialCopyExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); parallelVerifyExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); verifyLatch.countDown(); } catch (InterruptedException e) { Log.e(TAG, "线程池关闭异常", e); } }).start(); } // 拷贝逻辑方法 private void copyPackageFile(File srcFile, File destFile) throws IOException { // 实现文件拷贝逻辑 Files.copy(srcFile.toPath(), destFile.toPath(), StandardCopyOption.REPLACE_EXISTING); } /** * 更新包的进度,并限制最大为 MAX_PACKAGE_PROGRESS */ private void updatePackageProgress(String packageName, long processed, long total, int stage) { double stageRatio = (double) processed / total; double progress = 0.0; switch (stage) { case STAGE_COPY: progress = MAX_PACKAGE_PROGRESS / 3 * stageRatio; break; case STAGE_VERIFY: progress = MAX_PACKAGE_PROGRESS / 3 + MAX_PACKAGE_PROGRESS / 3 * stageRatio; break; case STAGE_EXTRACT_ONLY: progress = MAX_PACKAGE_PROGRESS / 3 * 2 + MAX_PACKAGE_PROGRESS / 3 * stageRatio; break; } packageProgressMap.put(packageName, Math.min(progress, MAX_PACKAGE_PROGRESS)); } /** * 串行拷贝任务 */ private class SerialCopyTask implements Runnable { private final File packageFile; private final ExecutorService parallelExecutor; private final File destFile; // 添加 destFile public SerialCopyTask(File packageFile, File destFile, ExecutorService parallelExecutor) { this.packageFile = packageFile; this.destFile = destFile; this.parallelExecutor = parallelExecutor; } @Override public void run() { if (isCancelled) { allPackagesLatch.countDown(); return; } String packageName = packageFile.getName(); // 阶段2: 解密验签 try { boolean verifyResult = dataVerification(destFile.getAbsolutePath(), new DecryptUtil.ProgressCallback() { @Override public void onProgress(long processed, long total) { packageStageMap.put(packageName, STAGE_VERIFY); updatePackageProgress(packageName, processed, total, STAGE_VERIFY); updateProgress("解密验签 %s: %s/%s", packageName, processed, total); } }); if (!verifyResult || isCancelled) { updateSuccess = false; allPackagesLatch.countDown(); return; } } catch (Exception e) { Log.e(TAG, "解密验签失败", e); updateSuccess = false; allPackagesLatch.countDown(); return; } // 解密验签完成,触发 verifyLatch verifyLatch.countDown(); allPackagesLatch.countDown(); } /** * 并行处理任务(解密验签、解压) */ private class PostCopyProcessingTask implements Runnable { private final File packageFile; private final File destFile; private final CountDownLatch allPackagesLatch; private final CountDownLatch verifyLatch; public PostCopyProcessingTask(File packageFile, File destFile, CountDownLatch allPackagesLatch, CountDownLatch verifyLatch) { this.packageFile = packageFile; this.destFile = destFile; this.allPackagesLatch = allPackagesLatch; this.verifyLatch = verifyLatch; } @Override public void run() { if (isCancelled) { allPackagesLatch.countDown(); verifyLatch.countDown(); return; } String packageName = packageFile.getName(); try { boolean verifyResult = dataVerification(destFile.getAbsolutePath(), new DecryptUtil.ProgressCallback() { @Override public void onProgress(long processed, long total) { packageStageMap.put(packageName, STAGE_VERIFY); updatePackageProgress(packageName, processed, total, STAGE_VERIFY); updateProgress("解密验签 %s: %s/%s", packageName, processed, total); } }); if (!verifyResult || isCancelled) { updateSuccess = false; } } catch (Exception e) { Log.e(TAG, "解密验签失败", e); updateSuccess = false; } finally { allPackagesLatch.countDown(); verifyLatch.countDown(); } } } private class SerialExtractTask implements Runnable { private final File packageFile; public SerialExtractTask(File packageFile) { this.packageFile = packageFile; } @Override public void run() { if (isCancelled) { allPackagesLatch.countDown(); return; } String packageName = packageFile.getName(); File destFile = new File(storageDir, packageName); // 阶段3: 解压 try { boolean extractResult = FileUtilszwx.extractZipWithProgress(destFile, storageDir, (extracted, total) -> { packageStageMap.put(packageName, STAGE_EXTRACT_ONLY); updatePackageProgress(packageName, extracted, total, STAGE_EXTRACT_ONLY); updateProgress("解压 %s: %s/%s", packageName, extracted, total); }); if (!extractResult || isCancelled) { updateSuccess = false; allPackagesLatch.countDown(); return; } } catch (Exception e) { Log.e(TAG, "解压失败", e); updateSuccess = false; allPackagesLatch.countDown(); return; } // 删除升级包 if (!destFile.delete()) { Log.w(TAG, "删除升级包失败: " + destFile.getName()); } // 最终进度设为最大值 packageProgressMap.put(packageName, MAX_PACKAGE_PROGRESS); allPackagesLatch.countDown(); // 任务完成 } } } //------------------------------------------------------- } 这是目前的代码,你需要做的是准备好代码尾部的方法,以便下一步在protected Integer doInBackground(Void... voids) {中调用它们来实现新的更新流程
最新发布
08-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值