线程、线程池、锁

面试官:你给我说一下线程池里面的几把锁。 你好呀,我是歪歪。 最近有个读者给我说,面试聊到线程池的时候,相谈甚欢,基本都回答上来了,但是其中有一个问题直接把他干懵逼了。 面试官问他:你说一下线程池里面的锁吧。 结果他关于线程池的知识点其实都是在各个博客或者面经里面看到的,没有自己去翻阅过源码,也就根本就没有注意过线程池里面还有锁的存在。 他还给我抱怨: 他这么一说,我也觉得,好像大家聊到线程池的时候,都没有怎么聊到里面用到的锁。 确实是存在感非常低。 要不我就安排一下? mainLock 其实线程池里面用到锁的地方还是非常 阅读详情

线程概念

线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。

线程生命周期

  1. 新建(New)‌:线程对象被创建但尚未启动 Thread thread = new Thread();
  2. ‌就绪(Runnable)‌:线程已准备好运行,等待CPU调度,start()只能调用一次,多次调用会抛出IllegalThreadStateException
  3. ‌运行(Running)‌:线程正在执行 cup执行
  4. ‌阻塞(Blocked)‌:线程等待某个条件(如I/O操作、锁等)
  5. 等待:await(),sleep(),join()
  6. ‌终止(Terminated)‌:线程执行完毕或异常退出

线程的 start 方法和 run 方法有什么区别?

public class Demo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /**
         * 1.直接重写run() 或继承Thread类再重写run()
         */
        Thread thread = new Thread() {
            @Override
            public void run() {
                System.out.println("Thread");
            }
        };
        // 开启线程
        thread.start();

        /**
         * 2.lambda、内部类或线程类方式实现Runnable接口,实现run()方法
         * 再交给Thread 类
         */
        Thread runThread = new Thread(() -> {
            System.out.println("Runnable");
        });
        // 开启线程
        runThread.start();

        /**
         * 3.lambda、内部类或线程类方式实现Callable接口,实现call()方法
         * 再交给Thread 类:FutureTask本质也是Runnable实现类
         */
        FutureTask<String> futureTask = new FutureTask<String>(() -> {
            System.out.println("Callable");
            return "CallableThread";
        });
        Thread callThread = new Thread(futureTask);
        // 开启线程
        callThread.start();
        // 获取call()方法的返回值
        String s = futureTask.get();
        System.out.println("call()方法的返回值:"+s);
    }

}

线程实现方式

  1. ‌用户级线程‌:由用户空间的线程库实现

    • 优点:不依赖操作系统,切换快
    • 缺点:一个线程阻塞会导致整个进程阻塞

public class UserLevelThread {
    public static void main(String[] args) {
        // 模拟用户级线程 - 实际Java不直接支持纯用户级线程
        Runnable task1 = () -> System.out.println("用户线程1运行");
        Runnable task2 = () -> System.out.println("用户线程2运行");
        
        // 在单内核线程上顺序执行
        task1.run();
        task2.run();
    }
}
  1. ‌内核级线程‌:由操作系统内核直接支持

    • 优点:一个线程阻塞不会影响其他线程
    • 缺点:创建和切换需要系统调用,开销较大

public class KernelThread {
    public static void main(String[] args) {
        // 真实内核线程
        Thread t1 = new Thread(() -> {
            System.out.println("内核线程1 ID: " + Thread.currentThread().getId());
        });
        
        Thread t2 = new Thread(() -> {
            System.out.println("内核线程2 ID: " + Thread.currentThread().getId());
        });
        
        t1.start();
        t2.start();
    }
}
  1. ‌混合实现‌:结合两者优点(如Java的线程模型)


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class HybridModel {
    public static void main(String[] args) {
        // 线程池实现混合模型
        ExecutorService pool = Executors.newFixedThreadPool(2);
        
        // 提交多个任务
        for (int i = 0; i < 5; i++) {
            final int taskId = i;
            pool.execute(() -> {
                System.out.println("任务" + taskId + "在" + 
                    Thread.currentThread().getName() + "执行");
            });
        }
        pool.shutdown();
    }
}

ThreadLocal

1. 一句话总结‌

ThreadLocal 就像给‌每个线程发了一个专属的储物柜‌,每个线程只能存取自己的东西,互相看不到对方柜子里的内容。


‌2. 生活化比喻‌
  • ‌场景‌:公司更衣室
    • 每个员工(线程)有自己独立的柜子(ThreadLocal)。
    • 员工A 往自己柜子里放了一双鞋,员工B 完全不知道,也拿不到。
    • 员工离职(线程结束)时,柜子会被清空(避免内存泄漏)。

‌3. 解决了什么问题?‌
  • ‌问题‌:多线程共享变量时,会打架(线程不安全)。
    • 比如:10个线程同时修改同一个变量 count++,结果可能错乱。
  • ‌ThreadLocal 方案‌:
    • 直接给每个线程发一个独立的 count 副本,各自玩自己的,互不干扰。

‌4. 代码例子(秒懂版)
public class ThreadLocalDemo {
    // 1. 创建一个ThreadLocal(相当于发储物柜)
    private static ThreadLocal<String> name = new ThreadLocal<>();

    public static void main(String[] args) {
        // 线程1:存自己的名字
        new Thread(() -> {
            name.set("张三"); // 存到自己的柜子
            System.out.println("线程1的名字:" + name.get()); // 只能拿到"张三"
        }).start();

        // 线程2:存自己的名字
        new Thread(() -> {
            name.set("李四"); // 存到自己的柜子
            System.out.println("线程2的名字:" + name.get()); // 只能拿到"李四"
        }).start();
    }
}

核心特点‌:

  • 线程隔离:变量对每个线程独立可见
  • 无锁化:天然避免线程安全问题
2. ‌底层原理‌
  • ‌数据结构‌:每个线程(Thread类)内部维护一个ThreadLocalMap(类似HashMap),键为ThreadLocal实例,值为存储的变量。
  • ‌哈希冲突解决‌:开放地址法(线性探测)。
3. ‌核心方法‌
方法作用
get()获取当前线程的变量副本
set(T value)设置当前线程的变量副本
remove()移除当前线程的变量副本(防止内存泄漏)
initialValue()覆盖此方法可定义初始值(默认返回null)
4. ‌内存泄漏问题‌
  • ‌原因‌:
    • ThreadLocalMap的键是弱引用(WeakReference<ThreadLocal>),但值是强引用。
    • 若ThreadLocal实例被回收,但线程未终止,会导致value无法被回收。
  • ‌解决方案‌:
    • 显式调用remove()清理条目。
    • 使用static final修饰ThreadLocal实例(延长生命周期)。
5. ‌典型应用场景‌
  • ‌数据库连接管理‌:每个线程维护独立的Connection(如 Spring 的TransactionSynchronizationManager)。
  • ‌用户会话信息‌:存储当前请求的用户身份(如 Spring Security 的SecurityContextHolder)。
  • ‌日期格式化‌:避免SimpleDateFormat的线程不安全问题。
6. ‌与同步机制对比‌
特性ThreadLocalsynchronized/Lock
数据隔离线程独享共享数据+同步访问
性能无锁,更高性能有锁,可能阻塞
适用场景线程间数据隔离线程间数据共享

Volitale

volatile 是 Java 中用于修饰变量的关键字,主要解决多线程环境下的‌内存可见性‌和‌指令重排序‌问题。
‌核心特性‌:

  • ‌可见性‌:保证变量修改后立即对其他线程可见
  • ‌有序性‌:禁止指令重排序优化
2. ‌底层原理‌
  • ‌内存屏障(Memory Barrier)‌:
    • 写操作:强制将工作内存中的修改刷新到主内存
    • 读操作:强制从主内存重新加载变量值
  • ‌JMM(Java Memory Model)‌:遵循 happens-before 规则,确保多线程操作的顺序性
3. ‌适用场景‌
场景说明
状态标志位如 while (!stop) 循环退出控制
单例模式(DCL)双重检查锁定中修饰实例变量(防止指令重排序)
多线程共享变量简单共享变量(不保证原子性,如 i++ 仍需同步)
4. ‌与 synchronized 对比‌
特性volatilesynchronized
原子性不保证(如 i++)保证
阻塞非阻塞阻塞
性能更高(无锁)较低(上下文切换开销)
作用范围仅修饰变量修饰方法/代码块
5. ‌代码示例‌
public class VolatileDemo {
    private volatile boolean flag = false;

    public void start() {
        new Thread(() -> {
            while (!flag) {
                // 循环直到 flag 变为 true
            }
            System.out.println("Thread stopped by flag");
        }).start();

        new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            flag = true; // 修改 flag 值
            System.out.println("Flag set to true");
        }).start();
    }

    public static void main(String[] args) {
        new VolatileDemo().start();
    }
}

‌输出‌:

Flag set to true

Thread stopped by flag

6. ‌注意事项‌
  • ‌不保证原子性‌:复合操作(如 count++)仍需使用 synchronized 或 AtomicInteger
  • ‌性能影响‌:频繁读写 volatile 变量会强制内存同步,可能降低性能
  • ‌替代方案‌:
    • 原子类(AtomicInteger 等)
    • final 不可变对象
7. ‌常见误区‌
  • ‌误区1‌:认为 volatile 能替代锁(实际仅解决可见性和有序性)
  • ‌误区2‌:滥用 volatile 导致伪共享(False Sharing)问题
8. ‌扩展:DCL 单例模式
public class Singleton {
    private static volatile Singleton instance;

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton(); // 防止指令重排序
                }
            }
        }
        return instance;
    }
}

线程池的概念

线程池是一种多线程处理形式,它预先创建一组线程并管理它们的生命周期,避免了频繁创建和销毁线程的开销。线程池的核心思想是‌线程复用‌,通过维护一个线程队列来执行多个任务。

线程池分类

java.util.concurrent包下的Excutor类创建线程池

Executors.newSingleThreadExecutor();

Executors.newScheduledThreadPool(int corePoolSize);

Executors.newCachedThreadPool();

Executors.newFixedThreadPool(int nThreads);

Spring的封装线程池

@Bean(name = "")
    public ThreadPoolTaskExecutor readPoolTaskExecutor() {
        ThreadPoolTaskExecutor billDeductExecutor = new ThreadPoolTaskExecutor();
        //核心线程数目 ,cpu个数 * 2
        billDeductExecutor.setCorePoolSize(Runtime.getRuntime().availableProcessors() * 2);
        //指定最大线程数
        billDeductExecutor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 2);
        //队列中最大的数目
        billDeductExecutor.setQueueCapacity(128);
        //线程空闲后的最大存活时间,单位:s
        billDeductExecutor.setKeepAliveSeconds(60);
        // 线程池对拒绝任务(无线程可用)的处理策略
        billDeductExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //线程名称前缀
        billDeductExecutor.setThreadNamePrefix("OperatorBillThreadPool-");
        return billDeductExecutor;
    }

定时任务线程池(ScheduledThreadPool)

/**
     * 执行周期性或定时任务
     */
    @Bean(name = "scheduledExecutorService")
    protected ScheduledExecutorService scheduledExecutorService() {
        return new ScheduledThreadPoolExecutor(corePoolSize,
                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build()) {
            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                super.afterExecute(r, t);
                Threads.printException(r, t);
            }
        };
    }


/**
     * 任务是否执行心跳维持任务
     *
     * @param operatorCode 运营商编码
     * @return 任务
     */
    private ScheduledFuture<?> keepAlive(String operatorCode) {
        String hbKey = OPERATOR_STATE_COMPARE_KEY + operatorCode + ":hearBeat";
        return scheduledExecutorService.scheduleAtFixedRate(() -> {
            log.error("OrderOperatorStaCmpTask|operatorCode={}|keepAlive", operatorCode);
            redisCache.setCacheObject(hbKey, "1", 32L, TimeUnit.SECONDS);
        }, 0L, 30L, TimeUnit.SECONDS);
    }

分治任务计算线程池

@Bean(name = "billCalculateThreadPool")
	public ForkJoinPool billCalculateThreadPool() {
		return new ForkJoinPool(10);
	}

ForkJoinPool的核心特点

ForkJoinPool是Java 7引入的一种特殊线程池,专为‌分治算法‌和‌递归任务‌设计,采用‌工作窃取(work-stealing)‌算法实现高效并行计算。

与普通线程池(ThreadPoolExecutor)的主要区别

特性ForkJoinPoolThreadPoolExecutor
‌设计目标‌处理可分解的并行任务处理独立任务
‌任务队列‌每个线程有自己的双端队列共享的任务队列
‌任务调度‌工作窃取算法先进先出(FIFO)
‌任务类型‌ForkJoinTask(RecursiveAction/RecursiveTask)Runnable/Callable
‌适用场景‌递归/分治任务(如归并排序)常规异步任务

ForkJoinPool的优势

  1. ‌工作窃取算法‌

    • 每个线程维护自己的任务队列

    • 空闲线程可以从其他线程队列"窃取"任务

    • 减少线程竞争,提高CPU利用率

  2. ‌更适合递归任务‌

    • 自动处理任务分解和结果合并

    • 简化分治算法的并行实现

  3. ‌更优的负载均衡‌

    • 动态平衡各线程的工作量

    • 避免某些线程空闲而其他线程过载

  4. ‌减少同步开销‌

    • 本地队列操作减少锁竞争

    • 适合计算密集型任务

ForkJoinPool的局限性

  1. ‌不适合I/O密集型任务‌

    • 设计初衷是CPU密集型计算

    • 线程阻塞会降低工作窃取效率

  2. ‌任务分解需要成本‌

    • 小任务分解可能得不偿失

    • 需要合理设置阈值

  3. ‌调试复杂度高‌

    • 递归/并行执行路径难以跟踪

    • 异常处理更复杂

  4. ‌内存消耗较大‌

    • 每个线程维护独立队列

    • 任务对象较多时占用更多内存

使用场景建议

‌适合使用ForkJoinPool的情况‌:

  • 递归算法(如快速排序、归并排序)

  • 可分解的大规模计算任务

  • 需要自动任务分解/结果合并的场景

  • CPU密集型并行计算

‌适合使用ThreadPoolExecutor的情况‌:

  • 独立任务处理(如Web请求)

  • I/O密集型操作

  • 不需要任务分解的常规异步任务

  • 需要更精细控制线程行为的场景

性能对比示例

对于计算斐波那契数列:

  • ForkJoinPool在n>30时优势明显

  • ThreadPoolExecutor在小规模计算(n<20)时更高效

对于文件处理:

  • ThreadPoolExecutor在I/O操作上表现更好

  • ForkJoinPool可能因线程阻塞而性能下降

自定义线程池创建

更灵活的方式是直接使用ThreadPoolExecutor构造函数:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    ThreadFactory threadFactory,
    RejectedExecutionHandler handler
);

参数详解

  1. ‌corePoolSize‌ (核心线程数)

    • 线程池中保持的最小线程数
    • 即使线程空闲也不会被回收(除非设置allowCoreThreadTimeOut)
  2. ‌maximumPoolSize‌ (最大线程数)

    • 线程池允许的最大线程数
    • 当工作队列满时,会创建新线程直到达到此值
  3. ‌keepAliveTime‌ (线程空闲时间)

    • 非核心线程的空闲存活时间
    • 超过此时间且线程数大于corePoolSize时,线程会被回收
  4. ‌unit‌ (时间单位)

    • keepAliveTime的时间单位(TimeUnit.SECONDS等)
  5. ‌workQueue‌ (工作队列)

    • 保存待执行任务的阻塞队列
    • 常见实现:
      • ArrayBlockingQueue: 有界队列
      • LinkedBlockingQueue: 无界队列
      • SynchronousQueue: 不存储元素的队列
  6. ‌threadFactory‌ (线程工厂)

    • 用于创建新线程
    • 可以自定义线程名称、优先级等
  7. ‌rejectedExecutionHandler‌ (拒绝策略)

    • 当线程池和工作队列都满时的处理策略
    • 内置策略:
      • AbortPolicy: 抛出RejectedExecutionException(默认)
      • CallerRunsPolicy: 由调用线程执行该任务
      • DiscardPolicy: 直接丢弃任务
      • DiscardOldestPolicy: 丢弃队列中最老的任务

线程池工作流程

  1. 提交任务时,如果当前线程数 < corePoolSize,创建新线程执行任务
  2. 如果线程数 ≥ corePoolSize,将任务放入工作队列
  3. 如果队列已满且线程数 < maximumPoolSize,创建新线程执行任务
  4. 如果队列已满且线程数 = maximumPoolSize,执行拒绝策略

最佳实践

  1. 根据任务类型选择合适线程池
  2. 合理设置核心和最大线程数
  3. 选择合适的队列容量
  4. 为线程池设置有意义的名称(通过ThreadFactory)
  5. 考虑使用自定义拒绝策略
  6. 监控线程池运行状态

线程池应用队列

‌1. ThreadPoolExecutor 队列选择‌

队列类型特点适用场景
‌LinkedBlockingQueue‌无界队列(默认),任务积压可能导致OOM任务量可控的短时异步任务
‌ArrayBlockingQueue‌有界队列,固定容量,队列满时触发拒绝策略需要限制资源消耗的稳定流量场景
‌SynchronousQueue‌直接传递队列,无缓冲,任务立即交给空闲线程或新建线程高吞吐量、瞬时高并发任务
‌PriorityBlockingQueue‌优先级队列,任务按优先级排序需要任务优先级调度的场景

‌推荐组合‌:

  • newFixedThreadPool + LinkedBlockingQueue(默认)
  • newCachedThreadPool + SynchronousQueue(默认)

‌2. ScheduledThreadPoolExecutor 队列‌

队列类型特点必要性
‌DelayedWorkQueue‌内部专用延迟队列,按任务触发时间排序必须使用(强制内置实现)

‌注意‌:无法自定义队列,所有定时任务均依赖此队列。


‌3. ForkJoinPool 队列‌

队列类型特点必要性
‌Work-Stealing队列‌每个线程维护双端队列,空闲线程可窃取其他队列任务必须使用(强制内置实现)

‌优势‌:自动负载均衡,适合递归分治任务。


‌4. 特殊场景队列选择‌

场景推荐队列原因
‌高吞吐+低延迟‌SynchronousQueue避免任务排队,直接分配线程
‌资源严格限制‌ArrayBlockingQueue + 拒绝策略防止任务无限堆积导致OOM
‌任务优先级差异大‌PriorityBlockingQueue确保高优先级任务优先执行
‌批量任务处理‌LinkedBlockingQueue缓冲任务,平衡生产者和消费者速度

‌5. 拒绝策略搭配建议‌

选择队列时需同步考虑拒绝策略(如AbortPolicy、CallerRunsPolicy等),例如:

  • ‌ArrayBlockingQueue‌ + AbortPolicy:快速失败,保护系统稳定性
  • ‌LinkedBlockingQueue‌ + CallerRunsPolicy:降级为同步执行,避免丢失任务

‌总结‌

  • ‌常规任务‌:优先选LinkedBlockingQueue(平衡性最佳)
  • ‌定时任务‌:强制使用DelayedWorkQueue
  • ‌分治任务‌:强制使用Work-Stealing队列
  • ‌极端场景‌:根据吞吐量/资源限制选择SynchronousQueue或ArrayBlockingQueue

合理搭配队列与线程池参数(核心线程数、最大线程数等)才能最大化性能。

锁的分类

‌1. 按线程竞争策略分类‌
类型特点适用场景
‌悲观锁‌默认会发生冲突,操作前先加锁(如synchronized, ReentrantLock)写多读少、冲突概率高的场景
‌乐观锁‌假设不会冲突,提交时检查版本(如CAS, AtomicInteger)读多写少、冲突概率低的场景

‌2. 按资源共享策略分类‌
类型特点示例
‌独占锁(排他锁)‌同一时刻只允许一个线程访问(如ReentrantLock)数据库行锁、文件写入锁
‌共享锁‌允许多个线程同时读取(如ReentrantReadWriteLock.ReadLock)数据库表级锁、缓存读锁

‌3. 按锁的实现方式分类‌
类型实现原理
‌内置锁‌JVM 原生支持(synchronized关键字)
‌显式锁‌JDK 提供的锁接口(Lock接口,如ReentrantLock)
‌分布式锁‌跨进程协调(如 Redis 的 SETNX、ZooKeeper 临时节点)
‌自旋锁‌线程循环尝试获取锁(如AtomicBoolean的compareAndSet)

‌4. 按锁的公平性分类‌
类型特点示例
‌公平锁‌按请求顺序分配锁(防止线程饥饿)new ReentrantLock(true)
‌非公平锁‌允许插队(性能更高,但可能造成饥饿)synchronized、ReentrantLock()

‌5. 按锁的重入性分类‌
类型特点示例
‌可重入锁‌同一线程可重复获取锁(防止死锁)synchronized、ReentrantLock
‌不可重入锁‌线程重复获取会阻塞自身(易死锁)自定义简单锁

‌6. 按锁的粒度分类‌
类型特点示例
‌偏向锁‌无竞争时消除同步开销(JVM 优化)JDK6+ 默认开启
‌轻量级锁‌短时竞争时用CAS替代阻塞JVM 自动升级
‌重量级锁‌线程竞争激烈时,通过操作系统互斥实现synchronized 最终状态

‌7. 特殊锁类型‌
类型特点使用场景
‌分段锁‌将数据分段加锁(如ConcurrentHashMap)高并发集合类
‌读写锁‌读共享,写互斥(如ReentrantReadWriteLock)读多写少场景(缓存)
‌邮戳锁‌乐观读锁(StampedLock)极高性能读场景
‌条件锁‌基于条件阻塞(如Condition.await())生产者消费者模型

‌8. 锁的升级过程(JVM 优化)‌

mermaidCopy Code

graph LR A[无锁] -->|首次访问| B[偏向锁] B -->|发生竞争| C[轻量级锁] C -->|竞争加剧| D[重量级锁]


‌9. 选锁黄金法则‌
  1. ‌简单场景‌ → 优先用 synchronized(自动释放、JVM 优化)
  2. ‌高性能需求‌ → 考虑 ReentrantLock + CAS(可控性强)
  3. ‌读多写少‌ → 选择 ReadWriteLock 或 StampedLock
  4. ‌分布式环境‌ → Redis/ZooKeeper 分布式锁
  5. ‌锁细化‌ → 分段锁或并发集合类

💡 ‌锁性能口诀‌:
无锁 > 偏向锁 > 轻量级锁 > 重量级锁
乐观锁 > 悲观锁
读锁 > 写锁


‌10. 经典锁对比表‌
特性synchronizedReentrantLockReadWriteLock
锁获取方式JVM 隐式获取代码显式控制显式控制读/写锁
可中断❌✅ (lockInterruptibly)✅
公平锁❌✅ (可配置)✅ (可配置)
条件等待单一 wait()/notify()多 Condition支持
性能JDK6+ 大幅优化高竞争下更优读多写少场景最优
锁释放自动释放必须手动 unlock()手动释放

ROS2中间件选型指南:FastDDS与CycloneDDS零拷贝机制对比与实战 在机器人开发中,通信中间件是连接分布式节点的核心纽带,其性能直接影响系统的实时性与可靠性。DDS作为ROS2默认的通信标准,通过发布订阅模型和QoS策略,为高频大带宽场景提供了灵活的数据分发能力。并行计算与高性能传输的需求,推动了零拷贝技术的演进——从传统序列化到共享内存乃至指针传递,旨在减少数据复制开销、降低延迟。在激光雷达点云、相机图像等场景下,中间件的选型尤为关键。FastDDS凭借与ROS2的深度集成和丰富文档成为入门首选,而CycloneDDS在低延迟和资源占用上表现更优,借助iceoryx实现了 阅读详情

相关推荐

OpenBCI脑电数据处理实战:用MNE库从Raw对象到可视化分析全流程

本文提供了使用MNE-Python库处理OpenBCI脑电数据的完整实战指南。从通过BrainFlow库获取原始数据流、创建核心的Raw对象,到进行工频滤波、带通滤波等关键预处理步骤,最后实现时域信号、功率谱密度及地形图等多种专业可视化分析,手把手教你完成脑机接口数据处理的全流程。

gin88的博客 369

锁升级及线程池相关

在JVM底层实现锁的过程中,有三类锁:偏斜锁、轻量级锁、重量级锁在Java6之前,synchronized的实现完全依靠重量级锁(系统内的互斥锁),从用户态转为内核态非常消耗资源。偏斜锁、轻量级锁、重量级锁。所谓的升级、降级,就是JVM优化synchronized运行的机制,当JVM检测到不同的竞争状况时,会自动切换到适合的锁实现,这种切换就是锁的升级、降级。偏向锁只有单线程执行情况下,该线程在后续访问时,便会自动获取锁。

fada_da_da的博客 1013

Android13配置selinux让system应用可读sys,proc,SN号

Android13预置的system应用,需要读/sys, /proc目录,读(SN)serial number号, 需要修改selinux配置,否则会报avc错.其修改方法会比Android11复杂一些.。

zmlovelx(帅得不敢出门 程序员群31843264) 2654

线程池、锁策略

本文介绍了线程池和定时器的实现原理,以及常见的锁策略。线程池通过预先创建固定数量的线程并复用,避免了频繁创建销毁线程的开销。定时器基于优先级队列或时间轮实现,可精确或高效地执行定时任务。文章详细分析了各种锁策略,包括乐观锁/悲观锁、重量级锁/轻量级锁、读写锁等,并深入探讨了synchronized的工作原理,包括其自适应特性、锁升级过程(从偏向锁到轻量级锁再到重量级锁)以及可重入、非公平等特点。最后总结了锁策略的选择依据和使用场景,为并发编程提供了实用的技术参考。

z141042的博客 1260

Android Studio打包全攻略---从入门到精通

初出茅庐 手动打包怎么手动打包项目写完了,现在需要把应用上传到市场,问题出现—怎么把代码变成.apk(Android的可安装文件)。 1. 创建签名文件 2. 填写好签名参数 3. 生成APK 注意:签名的密码和密匙的密码注意保管,不要忘了,签名文件别泄漏了,也别搞丢了为什么要打包我最开始就有这个疑问,我们的代码不是点了下运行按钮就直接安装到手机上了吗,我们在在项目Project

我早就想,要这样载着你,翻山越岭 2万+

Vue3集成百度实时语音识别

Vue3集成百度实时语音识别

weixin_61769998的博客 548

java多线程与线程池-02线程池与锁

ThreadPoolExecutor是应用最广的底层线程池类,它实现了Executor和ExecutorService接口。

天空鸟的博客 679

数电实验,如何安装Quartus II软件?

数电实验第一步,安装软件Quartus II! 安装这个软件可以说是很折磨我了,依然是failed很多次之后终于可以了! 能成功安装,多亏了网络上的各路大神!!!不胜感激 现在分享经验如下: ps:我分享的是Quartus II 14.0版本的软件及破解器安装使用方法 注意!想要在电脑上顺利安装,前提条件是电脑有10G以上内存!!! 友情提示:建议整个下载过程中,提前关掉所有杀毒、电脑

一个程序媛的成长记录❤ 3654

锁与线程池关系

锁与线程池关系前言一、锁实现上自身的问题二、线程池1.概念2.加入正确的线程池总结 前言 synchronize关键字基于JVM的监视器锁指令实现同步锁,同时提供了另外一种显示锁,将主动权握在程序员手中,实现锁的灵活使用。 一、锁实现上自身的问题 synchronize简单粗暴的代码测试: 测试结果: 显示锁,ReentrantLock,同样简单粗暴测试代码: 测试结果: synchronize和显示锁都是是可重入的,只是,线程的等待队列都未做有界限制。 二、线程池 1.概念 线程池,存放着已经创

ch123456hy的博客 412

从被秒封到稳过Cloudflare!Canvas/WebGL/WebRTC多维度浏览器指纹隐身全实战

反爬和反反爬,本质上是一场持续的博弈,没有100%的隐身,只有不断升级的伪装。网上很多教程只给了个基础的噪声代码,却没讲透反爬的检测逻辑,导致你用了还是被封。这套方案的核心,不是简单的API重写,而是站在反爬的角度,模拟真实用户的所有特征,保证所有指纹的一致性、合理性、完整性。目前这套方案我用了半年,跑了上千万次请求,稳过国内国外99%的主流反爬平台,没有出现过一次因为指纹关联导致的批量封禁。大家有什么更狠的反爬场景,或者更好的伪装技巧,欢迎评论区一起交流。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1193

MATLAB - 机械臂手眼标定(眼在手内) - 估计安装在机器人上的移动相机的姿态

执行手眼校准有助于操作配备末端执行器(简称 “手”)的机械臂,该末端执行器依赖于摄像头提供的视觉数据。一旦完成了眼在手外的校准,机械臂就能准确地移动到摄像头识别的特定像素位置。这种能力是执行精确拾放任务(如分类、堆垛和分拣)的基础,即使在摄像机的确切位置和方向未知的情况下也是如此。机器人-摄像机系统有两种构型:眼在手内和眼在手外。在眼在手内构型中,摄像头直接安装在机器人手臂的末端执行器上。相反,在眼在手的构型中,摄像头固定在一个静止的物体上,机器人手臂在其视野内。

机器人控制与仿真应用 3348

锁与线程池的学习笔记

本文介绍了锁与线程池的基本概念及其实现。锁分为互斥锁和自旋锁,互斥锁适合处理复杂任务,而自旋锁适合简单任务。原子操作通过减少指令数量提升性能。线程池用于管理线程,避免频繁创建和销毁线程的开销,核心组件包括任务队列、执行队列和管理组件。线程池通过初始化、回调函数、任务推送和销毁等操作实现高效任务管理。代码示例展示了线程池的创建、任务处理及销毁过程,帮助理解其工作原理。

adagio9z的博客 1316

学Simulink——基于电能质量治理的场景实例:静止无功发生器(SVG)与并网逆变器的结合

本文详细介绍了基于Simulink的SVG与光伏并网逆变器联合仿真建模方法。系统包含光伏单元、SVG主电路、控制策略(无功检测+双闭环控制)等模块,通过ip-iq法实现动态无功补偿。仿真结果表明,SVG能快速响应负载变化,将功率因数提升至0.98以上,有效稳定母线电压。该方案为新能源并网系统提供了有功/无功协同控制解决方案,具有10ms级响应速度和±5kvar补偿能力。文章提供了完整的建模流程、控制算法实现和结果分析,可作为电力电子与电能质量治理领域的实践指导。

amy_mhd的博客 167

线程池+线程安全+常见锁

IT行业这么火,涌入的人很多,俗话说林子大了啥鸟都有,大佬和菜鸡们两极分化的越来越严重.为了让菜鸡们不太拖大佬的后腿,于是大佬们针对一些经典的常见的场景,给定了一些对应的解决方案,这个就是。

杀意感知的博客 800

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

线程/线程池/锁知识点介绍

文章目录一、多线程1.多线程实现方式2.线程安全3.JUC开发框架二、Threadlocal1.ThreadLocal介绍2.ThreadLocal实现原理3.ThreadLocal如何避免内存泄漏4.ThreadLocal使用场景三、AQS1.AQS介绍及应用2.AQS实现方式3.如何设计一个互斥的lock4.读写锁ReadWriteLock5.CountDownLactch6.CyclicBarrier四、线程池1.线程池简述2.线程池参数3.线程池实现机制(线程池原理)4.线程池配置方案及调优5.自定

tttalk的博客 1856

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

线程、线程池、Lock锁

1.线程:Thread 创建多线程的方法一: 一个进程可以拥有多个线程 .start多线程的启动 (1)创建一个类继承Thread (2)重写润run()创建多线程做什么事就放到run()内 (3)创建多线程的对象 (4)使用线程对象.start()方法启动 注意:(1)调用start() 方法 让线程 进入就绪状态 等待 CPU调度 (2)继承Thread类的情况下 可以使用 可以通过this.setName();进行名字的设置 可以通过this.getName();进行名字的获取 (3) 在非继承Thr

weixin_45290168的博客 242

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Lock锁、ThreadLocal、线程池、

一、Lock、interface jdk1.5以后 并发包Lock 手动开锁和释放 1、lock(); //开锁 2、lockInterruptibly(); //可中断锁,锁被别人抢到,中断等待 3、tryLock(); boolean //判断有没有被开锁,有就不运行了 4、tryLock(秒); //多长时间内又没有人占用 5、unlock(); //释放锁 .........

乌昂先生的博客 393

Java多线程总结(二)锁、线程池

  掌握Java中的多线程,必须掌握Java中的各种锁,以及了解Java中线程池的运用。关于Java多线程基础总结可以参考我的这篇博文Java多线程总结(一)多线程基础   转载请注明出处——http://www.cnblogs.com/zrtqsk/p/3784049.html,谢谢。    一、Java中锁 什么是锁。锁就是为了保护资源,防止多个线程同时操作资源时出错的机制。 我们先...

weixin_34313182的博客 185

初识linux之线程池与一些常见的锁

本文介绍了线程池的概念和简单模拟实现以及一些比较常用的锁,如自旋锁、读写锁的概念

Masquerena114514的博客 786

并发、线程、线程池、锁相关

并发:宏观上并行,微观上串行并行:一起执行串行:交替执行。

north___wind的博客 777

java线程池中锁机制_Java多线程总结(二)锁、线程池

本文转载地址:一、Java中锁什么是锁。锁就是为了保护资源,防止多个线程同时操作资源时出错的机制。我们先来看一下锁的类图:如图,Java中的锁有两个主要的根接口——Lock和ReadWriteLock,分别表示锁和读写锁。其中Lock的主要实现类是ReetrantLock。ReadWriteLock的主要实现类是ReetrantReadWriteLock。而ReetrantReadWriteLoc...

weixin_31083103的博客 716

基于无锁循环队列的线程池的实现

个人笔记:因为是跟着b站的教学视频以及文档初步学习,可能存在诸多的理解有误,对大家仅供借鉴,参考,然后是B站up阳哥的视频,我是跟着他学。大家有兴趣的可以到b站搜索。加油,一起学习。应用场景设计实现等待策略模块第一点,为啥需要封装不同的等待策略?第二点,有哪些等待策略?第三点,如何实现?对于第一个问题,是很容易根据常识得出结论的,就是具体问题,具体分析。具体场景,具体应对。在多线程编程的环境下,不同的应用场景,要求就需要应用不同的等待机制。每种等待策略。都有着它独特之处,有着它的特点。

小杰312的博客 1781

python3 线程 锁 线程池

线程使用 方式1 创建并立即执行 import _thread as thread import time # 为线程定义一个函数 def customize_function(thread_name, delay): sum = 0 while sum < 5: time.sleep(delay) # 休眠时间,单位秒 sum += 1 print("%s: %s" % (thread_name, time.ctime.

大数据开发 786

多线程+线程池,锁

创建线程的方法: 继承Thread 类 Thread 类本质上是实现了Runnable 接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过Thread 类的start()实例方法。start()方法是一个native 方法,它将启动一个新线程,并执行run()方法。 实现Runnable 接口 如果自己的类已经extends 另一个类,就无法直接extends Thread,此时,可以实现一个Runnable 接口; 启动线程需要实例化一个Thread,并传入实现runnable的实例

qq_42728113的博客 1122

锁以及线程池的使用

一、数据库的锁以及乐观锁 1.共享锁 共享锁(S锁):共享 (S) 用于不更改或不更新数据的操作(只读操作),如 SELECT 语句。如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁。获准共享锁的事务只能读数据,不能修改数据。 2.排他锁 排他锁(X锁):用于数据修改操作,例如 INSERT、UPDATE 或DELETE。确保不会同时同一资源进行多重更新。如果事务T对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。 3.乐观锁

Pan_Yang___的博客 334

【JAVA多线程18】线程池原理和锁

1 线程池 1.1 好处 1.2 作用 1.3 线程池创建方式 1.4 原理分析 1.5 线程池合理配置 2 锁的深度化 2.1悲观锁 2.2 乐观锁 2.3 重入锁 2.4 读写锁 2.5 CAS无锁机制 2.6 自旋锁 2.7 分布式锁 1 线程池 1.1 好处 1)降低资源消耗,重复利用已经创建好的线程,降低线程创建和销毁造成的消耗 2)提高响应速度,当任...

dcm19920115的博客 432
上一篇: JVM内存模型 + GC系统 + 类加载
下一篇: (未完结)阶段小总结(一)——大数据与Java
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值