Java多线程并发与加密算法和安全漏洞

目录

一、Java多线程并发

1.1 理解线程模型与内存语义

1.2 线程同步机制

1.3 并发工具类

1.4 线程池与任务管理机制

1.5 理解ThreadPoolExecutor的源码和原理

二、加密算法与安全漏洞

2.1 对称加密:AES、DES

2.2 非对称加密:RSA、DSA

2.3 摘要算法:MD5、SHA

2.4 XSS 跨站脚本攻击

2.5 SQL 注入

2.6 CSRF(跨站请求伪造)

2.7 JAR 包升级与依赖安全

一、Java多线程并发

1.1 理解线程模型与内存语义

首先明确

(1)进程:是一个正在执行中的程序。

每一个进程执行都是有一个执行顺序,这个顺序是一个执行路径,或者叫一个控制单元。

(2)线程:就是进程中的一个独立的控制单元。

线程在控制着进程的执行。

一个进程中至少有一个线程。

jvm启动的时候会有一个进程java.exe,该进程中至少有一个线程负责java程序的执行。而且这个线程运行的代码在main方法里,该线程称为主线程。

那么java对线程这类事物提供了一个描述,就是Thread类。

(3) 并行与并发

并行:多个处理器同时执行多个线程(物理层面的同时)。

并发:多个线程在同一处理器上交替执行(逻辑层面的同时)。

(4)同步机制与内存语义

synchronized关键字

  • 语义:确保同一时刻只有一个线程执行同步块,并在解锁时将工作内存的变量刷新到主内存,加锁时从主内存读取最新值。

volatile关键字

  • 语义

    • 保证变量的可见性:写操作会立即刷新到主内存,读操作会从主内存读取。
    • 禁止指令重排序:通过内存屏障确保特定操作的顺序。
  • 原子类(Atomic Classes) :通过 CAS(Compare-and-Swap)实现无锁原子操作,如AtomicInteger

  • 显式锁(Lock)ReentrantLock提供与synchronized类似的语义,但更灵活(可中断、可定时)。

  • 并发容器ConcurrentHashMapCopyOnWriteArrayList等,内部通过锁分段或写时复制保证线程安全

1.2 线程同步机制

传统同步方式

synchronized关键字

  • 作用范围

    • 实例方法:锁当前对象实例。
    • 静态方法:锁当前类的 Class 对象。
    • 代码块:锁指定对象。
js 复制代码
public class SynchronizedExample {
    private int count = 0;
    
    // 实例方法锁(this)
    public synchronized void increment() {
        count++;
    }
    
    // 静态方法锁(Class对象)
    public static synchronized void staticMethod() {
        // ...
    }
    
    // 代码块锁
    public void blockLock() {
        synchronized(this) {
            count++;
        }
    }
}

ait()notify()notifyAll()

  • 作用 :用于线程间协作,必须在synchronized块中调用。
js 复制代码
public class ProducerConsumer {
    private final List<Integer> buffer = new ArrayList<>();
    private final int MAX_SIZE = 10;
    
    public synchronized void produce(int value) throws InterruptedException {
        while (buffer.size() == MAX_SIZE) {
            wait(); // 等待消费者消费
        }
        buffer.add(value);
        notifyAll(); // 通知消费者
    }
    
    public synchronized int consume() throws InterruptedException {
        while (buffer.isEmpty()) {
            wait(); // 等待生产者生产
        }
        int value = buffer.remove(0);
        notifyAll(); // 通知生产者
        return value;
    }
}

JUC 包中的高级同步工具

1. ReentrantLock(可重入锁)

  • 特性 :与synchronized类似,但支持公平锁、可中断锁、条件变量。
js 复制代码
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockExample {
    private final Lock lock = new ReentrantLock();
    private int count = 0;
    
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock(); // 必须在finally中释放锁
        }
    }
}

ReadWriteLock(读写锁)

  • 特性:允许多个线程同时读,但写时互斥。适用于读多写少场景。
js 复制代码
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Cache {
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private Map<String, Object> cache = new HashMap<>();
    
    public Object get(String key) {
        rwLock.readLock().lock(); // 读锁
        try {
            return cache.get(key);
        } finally {
            rwLock.readLock().unlock();
        }
    }
    
    public void put(String key, Object value) {
        rwLock.writeLock().lock(); // 写锁
        try {
            cache.put(key, value);
        } finally {
            rwLock.writeLock().unlock();
        }
    }
}

Condition接口

  • 作用 :替代传统的wait()/notify(),支持多个等待队列。
js 复制代码
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class BoundedQueue {
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    private final Object[] items = new Object[10];
    private int count, head, tail;
    
    public void put(Object x) throws InterruptedException {
        lock.lock();
        try {
            while (count == items.length)
                notFull.await(); // 队列满时等待
            items[tail] = x;
            if (++tail == items.length)
                tail = 0;
            ++count;
            notEmpty.signal(); // 通知取元素线程
        } finally {
            lock.unlock();
        }
    }
}

1.3 并发工具类

CountDownLatch

  • 作用:让一个或多个线程等待其他线程完成操作。
js 复制代码
import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3);
        
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                System.out.println("子线程执行...");
                latch.countDown(); // 计数器减1
            }).start();
        }
        
        latch.await(); // 等待所有子线程完成
        System.out.println("所有子线程执行完毕");
    }
}

CyclicBarrier

  • 作用:让一组线程到达某个屏障时被阻塞,直到所有线程都到达后继续执行。
js 复制代码
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(3, () -> {
            System.out.println("所有线程准备就绪,开始执行...");
        });
        
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + " 准备就绪");
                    barrier.await(); // 等待其他线程
                    System.out.println(Thread.currentThread().getName() + " 开始执行");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

Semaphore(信号量)

  • 作用:控制同时访问特定资源的线程数量。
js 复制代码
import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    private static final int THREAD_COUNT = 10;
    private static final Semaphore SEMAPHORE = new Semaphore(3); // 允许3个线程同时访问
    
    public static void main(String[] args) {
        for (int i = 0; i < THREAD_COUNT; i++) {
            new Thread(() -> {
                try {
                    SEMAPHORE.acquire(); // 获取许可
                    System.out.println(Thread.currentThread().getName() + " 获取许可");
                    Thread.sleep(2000);
                    SEMAPHORE.release(); // 释放许可
                    System.out.println(Thread.currentThread().getName() + " 释放许可");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}
同步方式 适用场景 优点 缺点
synchronized 简单互斥场景 语法简洁,自动释放锁 不可中断,无法实现公平锁
ReentrantLock 复杂同步场景(公平锁、可中断锁) 灵活性高 需要手动释放锁
ReadWriteLock 读多写少场景 提高读并发 写锁可能饥饿
Atomic 简单原子操作(计数、ID 生成) 无锁,性能高 只能保证单个变量原子性
CountDownLatch 一个 / 多个线程等待其他线程 一次性使用 不可重置
CyclicBarrier 一组线程相互等待 可重复使用 实现复杂

1.4 线程池与任务管理机制

线程池的优势

  • 降低资源消耗:复用已创建的线程,减少线程创建和销毁的开销。
  • 提高响应速度:任务到达时无需等待线程创建,直接使用池中的线程执行。
  • 统一管理线程:控制最大并发数,避免资源耗尽,提供定时执行、定期执行等功能。

线程池的工作流程

  1. 提交任务 :调用execute(Runnable)submit(Callable)方法提交任务。

  2. 线程池判断

    • 核心线程数未满,创建新线程执行任务。
    • 核心线程已满任务队列未满,将任务放入队列。
    • 任务队列已满线程数未达最大,创建新线程执行任务。
    • 线程数已达最大 ,触发拒绝策略

1.5 源码

js 复制代码
public ThreadPoolExecutor(
    int corePoolSize,                      // 核心线程数
    int maximumPoolSize,                   // 最大线程数
    long keepAliveTime,                    // 线程空闲时间
    TimeUnit unit,                         // 时间单位
    BlockingQueue<Runnable> workQueue,     // 任务队列
    ThreadFactory threadFactory,           // 线程工厂
    RejectedExecutionHandler handler       // 拒绝策略
)

任务提交方法

  • execute(Runnable command) :提交无返回值的任务。
  • submit(Callable<T> task) :提交有返回值的任务,返回Future对象。
java 复制代码
状态控制:
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

// 高3位表示线程池状态,低29位表示线程数量
private static final int RUNNING    = -1 << COUNT_BITS;
private static final int SHUTDOWN   =  0 << COUNT_BITS;
private static final int STOP       =  1 << COUNT_BITS;
private static final int TIDYING    =  2 << COUNT_BITS;
private static final int TERMINATED =  3 << COUNT_BITS;

execute 方法核心逻辑

scss 复制代码
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    
    // 1. 核心线程未满,创建新线程
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    
    // 2. 核心线程已满,任务入队
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    
    // 3. 队列已满,尝试创建新线程
    else if (!addWorker(command, false))
        reject(command); // 4. 创建失败,触发拒绝策略
}

二、加密算法与安全漏洞

2.1 对称加密:AES、DES

AES(高级加密标准)

AES 是目前最流行的对称加密算法,取代了 DES。它支持 128、192 和 256 位密钥长度,分组长度为 128 位。其基本流程包括:

  1. 密钥扩展:将用户密钥扩展成多个轮密钥
  2. 初始轮:异或轮密钥
  3. 多轮处理:包括 SubBytes(字节替换)、ShiftRows(行移位)、MixColumns(列混合)和 AddRoundKey(轮密钥加)
  4. 最终轮:省略 MixColumns

DES(数据加密标准)

DES 是一种较旧的对称加密算法,密钥长度 56 位(实际 64 位,包含 8 位奇偶校验)。由于密钥过短,已不安全,逐渐被 AES 取代。其基本流程与 AES 类似但更简单,采用 Feistel 网络结构,经历 16 轮加密。

分组模式

  1. ECB(电子密码本)

    • 最简单的模式,将明文分成固定大小的块,每块单独加密
    • 相同明文块生成相同密文块,不安全,易受统计分析攻击
  2. CBC(密码块链接)

    • 每个明文块先与前一个密文块异或,再加密
    • 需要初始向量(IV),IV 必须随机且不重复使用
    • 提供了更好的安全性,但不支持并行处理
  3. GCM(计数器模式)

    • 结合了计数器模式(CTR)和 GMAC 认证
    • 提供加密和认证,支持并行处理
    • 需要随机 IV,推荐用于需要完整性保护的场景
js 复制代码
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

public class AESEncryption {
    // 生成随机密钥
    public static SecretKey generateKey(int keySize) throws Exception {
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(keySize, SecureRandom.getInstanceStrong());
        return keyGen.generateKey();
    }
    
    // 生成随机IV
    public static IvParameterSpec generateIV() {
        byte[] iv = new byte[16]; // AES块大小为16字节
        SecureRandom secureRandom = new SecureRandom();
        secureRandom.nextBytes(iv);
        return new IvParameterSpec(iv);
    }
    
    // 加密
    public static String encrypt(String plaintext, SecretKey key, IvParameterSpec iv) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key, iv);
        byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }
    
    // 解密
    public static String decrypt(String ciphertext, SecretKey key, IvParameterSpec iv) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, key, iv);
        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(ciphertext));
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }
}

2.2 非对称加密:RSA、DSA

RSA

  • 基于大整数因子分解难题
  • 既能用于加密,也能用于签名
  • 密钥长度通常为 2048 位或更高
  • 加密过程:密文 = 明文 ^E mod N
  • 解密过程:明文 = 密文 ^D mod N
  • 缺点:速度慢,通常用于交换对称密钥

DSA(数字签名算法)

  • 专门用于数字签名,不能用于加密
  • 基于离散对数难题
  • 与 RSA 相比,签名生成速度更快,但验证速度较慢
  • 通常与 SHA 系列算法配合使用
js 复制代码
import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;

public class RSAExample {
    // 生成密钥对
    public static KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        keyPairGen.initialize(2048);
        return keyPairGen.generateKeyPair();
    }
    
    // 加密
    public static String encrypt(String plaintext, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }
    
    // 解密
    public static String decrypt(String ciphertext, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(ciphertext));
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }
}

2.3 摘要算法:MD5、SHA

MD5

  • 生成 128 位哈希值
  • 已被证明不安全,存在碰撞攻击
  • 不推荐用于安全场景,仅用于文件完整性校验等非安全场景

SHA-1

  • 生成 160 位哈希值
  • 已被证明不安全,存在碰撞攻击
  • 逐渐被 SHA-2 和 SHA-3 取代

SHA-256/SHA-512

  • SHA-2 系列包括 SHA-224、SHA-256、SHA-384 和 SHA-512
  • 目前被广泛认为是安全的
  • SHA-256 生成 256 位哈希值,SHA-512 生成 512 位哈希值
java 复制代码
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class HashExample {
    // MD5(仅作示例,不推荐用于安全场景)
    public static String md5(String input) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] hashBytes = md.digest(input.getBytes(StandardCharsets.UTF_8));
        return bytesToHex(hashBytes);
    }
    
    // SHA-256
    public static String sha256(String input) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] hashBytes = md.digest(input.getBytes(StandardCharsets.UTF_8));
        return bytesToHex(hashBytes);
    }
    
    // 字节数组转十六进制字符串
    private static String bytesToHex(byte[] bytes) {
        StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append(String.format("%02x", b));
        }
        return result.toString();
    }
    
    // 加盐哈希示例
    public static String saltedHash(String password, String salt) throws NoSuchAlgorithmException {
        String saltedPassword = password + salt;
        return sha256(saltedPassword);
    }
}

2.4 XSS跨站脚本攻击

攻击类型

  1. 存储型 XSS

    • 恶意脚本存储在服务器端(如数据库)
    • 所有访问该页面的用户都会执行该脚本
    • 危害最大,如论坛、评论系统等
  2. 反射型 XSS

    • 恶意脚本通过 URL 参数传递
    • 服务器将参数内容反射到 HTML 响应中
    • 仅影响点击恶意链接的用户
  3. DOM 型 XSS

    • 攻击发生在客户端 DOM 处理阶段
    • 页面本身不改变,但用户浏览器中的 DOM 被修改
    • 通过 JavaScript 动态修改 DOM 时易受攻击

防护手段

  1. 输出转义

    • 对用户输入进行 HTML 实体编码
    • 如将<转为&lt;>转为&gt;
  2. HTML 过滤

    • 对用户输入的 HTML 进行白名单过滤
    • 只允许安全的标签和属性
  3. CSP(内容安全策略)

    • 通过 HTTP 头指定允许加载的资源来源
    • 防止加载恶意脚本
    • 示例:Content-Security-Policy: default-src 'self'; script-src 'self' trusted.example.com

2.6 CSRF (跨站请求伪造)

攻击原理

  • 攻击者诱导用户在已登录的网站上执行恶意操作
  • 利用用户的会话 Cookie 或认证信息
  • 例如:用户已登录银行网站,攻击者诱导用户访问恶意网站,该网站向银行网站发送转账请求

防护手段

  1. CSRF 令牌

    • 在表单或 URL 中包含随机令牌
    • 服务器验证请求中的令牌
  2. SameSite Cookie 属性

    • 设置 Cookie 的 SameSite 属性为 Strict 或 Lax
    • 阻止跨站请求携带 Cookie
    • 示例:Set-Cookie: session=12345; SameSite=Strict
  3. 验证请求来源

    • 检查 HTTP 头中的 Referer 或 Origin 字段
    • 确保请求来自合法来源

2.7 JAR包升级与依赖安全

漏洞检测

GitHub Dependabo

  • 自动检测和提醒依赖漏洞
  • 支持自动创建 PR 更新依赖

OWASP Dependency-Check

diff 复制代码
-   静态分析工具,检测项目依赖中的已知漏洞
-   支持 Maven、Gradle、npm 等多种构建工具

依赖冲突管理

  1. Maven 依赖处理

    • 使用mvn dependency:tree查看依赖树
    • 使用<exclusions>排除冲突依赖
  2. 版本规范

    • 在 Maven 中使用<dependencyManagement>
  3. 使用单一版本源

    • 避免从多个不同仓库引入相同依赖的不同版本
xml 复制代码
#### 使用 OWASP Dependency-Check
<!-- 在pom.xml中添加插件 -->
<build>
    <plugins>
        <plugin>
            <groupId>org.owasp</groupId>
            <artifactId>dependency-check-maven</artifactId>
            <version>8.3.1</version>
            <executions>
                <execution>
                    <goals>
                        <goal>check</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
相关推荐
ademen5 分钟前
spring4第6课-bean之间的关系+bean的作用范围
java·spring
cccl.5 分钟前
Java在word中指定位置插入图片。
java·word
kingbal6 分钟前
Elasticsearch:spring2.x集成elasticsearch8.x
java·spring2.x·elastic8.x
三两肉2 小时前
Java 中 ArrayList、Vector、LinkedList 的核心区别与应用场景
java·开发语言·list·集合
yuren_xia2 小时前
Spring Boot中保存前端上传的图片
前端·spring boot·后端
clk66073 小时前
SSM 框架核心知识详解(Spring + SpringMVC + MyBatis)
java·spring·mybatis
JohnYan5 小时前
Bun技术评估 - 04 HTTP Client
javascript·后端·bun
shangjg35 小时前
Kafka 的 ISR 机制深度解析:保障数据可靠性的核心防线
java·后端·kafka
青莳吖6 小时前
使用 SseEmitter 实现 Spring Boot 后端的流式传输和前端的数据接收
前端·spring boot·后端
我的golang之路果然有问题7 小时前
ElasticSearch+Gin+Gorm简单示例
大数据·开发语言·后端·elasticsearch·搜索引擎·golang·gin