并发编程原理与实战(一)精准理解线程的创建和停止

java并发编程(二)——如何正确停止一个线程? 原理介绍 首先,我们来复习如何启动一个线程,想要启动线程需要调用 Thread 类的 start() 方法,并在 run() 方法中定义需要执行的任务。启动一个线程非常简单,但如果想要正确停止它就没那么容易了。 通常情况下,我们不会手动停止一个线程,而是允许线程运行到结束,然后让它自然停止。但是依然会有许多特殊的情况需要我们提前停止线程,比如:用户突然关闭程序,或程序运行出错重启等。 在这种情况下,即将停止的线程在很多业务场景下仍然很有价值。尤其是我们想写一个健壮性很好,能够安全应对各种场景的程序时,正确停 阅读详情
什么是线程

很多人在接触多线程的时候,听的最多可能是“线程是操作系统进行调度的最小单位”,这可能又要问“什么是调度的最小单位”了,这样理解很抽象难懂。既然线程是跟编程有关,那我们就从代码的角度去理解。假设main方法中有三个methodA、methodB、methodC方法,在main方法中依次调用执行,main()->methodC()->methodB()->methodC(),main方法启动后主线程调用methodA、methodB、methodC方法的过程就是一条代码执行流。所以从代码的角度来讲,线程是一条代码执行流,完成一个特定的任务。

代码示例

public class MyThread {
    public static void main(String[] args) {
        methodA();
        methodB();
        methodC();
    }
    private static void methodC() {
    }
    private static void methodB() {
    }
    private static void methodA() {
    }
}

在这里插入图片描述

线程的创建方式

关于线程的创建方式,网上也是有不同的版本。我的理解是,本质上创建线程的方式只有一种,就是创建一个Thread对象,并调用Thread对象的start()方法启动线程,只是创建线程时重写run()方法实现特定任务代码的方式有多种方式而已。从Thread类的构造函数,理解线程的创建方式,下图是Thread类的相关构造函数。

有多少个构造函数就有多少中创建Thread对象的方式,但用不同的构造函数创建线程本质都是一样:创建Thread对象并调用start()方法来启动线程。接下来我们来看看java.util.concurrent.ThreadPoolExecutor中的线程池是如何创建线程的,如果对线程池还有没有了解,没关系,在这里我们只想了解jdk里面创建线程的方式,加深对线程创建方式的理解,避免上来就是死记硬背”继承Thread类或者实现Runnable接口“。

ThreadPoolExecutor类中有个addWorker的方法,主要是是往线程池中添加任务。我们摘取主要代码进行分析。

private boolean addWorker(Runnable firstTask, boolean core) {
    ...
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        //传入任务对象,创建Worker对象
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            ...
            if (workerAdded) {
                //启动线程
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

Worker是其中的一个内部类,封装了线程对象和任务对象。

private final class Worker
    extends AbstractQueuedSynchronizer
    implements Runnable
{
    ...
    /** worker运行的线程对象 */
    final Thread thread;
    /** worker运行的任务 */
    Runnable firstTask;
	...
    /**
     * Creates with given first task and thread from ThreadFactory.
     * @param firstTask the first task (null if none)
     */
    Worker(Runnable firstTask) {
        setState(-1); // inhibit interrupts until runWorker
        this.firstTask = firstTask;
        //从线程工厂中创建线程
        this.thread = getThreadFactory().newThread(this);
    }

    /** Delegates main run loop to outer runWorker  */
    public void run() {
        runWorker(this);
    }
	...
}

从上面的代码中可以看出,线程池的线程对象是从线程工厂中获取的。那么线程工厂又是如何创建线程的,我们接着往下看。
在这里插入图片描述

从ThreadPoolExecutor的构造函数中可以看出,创建线程池时可以指定线程工厂,如果不指定将会采用默认的线程工厂。

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}

调用Executors的defaultThreadFactory()方法创建线程工厂。

public static ThreadFactory defaultThreadFactory() {
    return new DefaultThreadFactory();
}

DefaultThreadFactory是Executors中的一个内部类,实现了线程工厂接口ThreadFactory。

static class DefaultThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    DefaultThreadFactory() {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
                              Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" +
                      poolNumber.getAndIncrement() +
                     "-thread-";
    }

    public Thread newThread(Runnable r) {
        //创建线程
        Thread t = new Thread(group, r,
                              namePrefix + threadNumber.getAndIncrement(),
                              0);
        if (t.isDaemon())
            t.setDaemon(false);
        if (t.getPriority() != Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}

ThreadFactory结果只有一个创建线程方法。

public interface ThreadFactory {

    /**
     * Constructs a new {@code Thread}.  Implementations may also initialize
     * priority, name, daemon status, {@code ThreadGroup}, etc.
     *
     * @param r a runnable to be executed by new thread instance
     * @return constructed thread, or {@code null} if the request to
     *         create a thread is rejected
     */
    Thread newThread(Runnable r);
}

从上面的代码中可以看出,线程工厂接口只有一个创建线程的方法,创建线程的具体过程由子类去实现,也是通过new Thread()的方式去创建线程的。这采用了面向对象设计中的一个核心原则:单一职责原则。也就是一个类应该只有一个职责。花了这么长的篇幅去了解线程池中创建线程的过程,目的就是理解创建线程的本质方式,相信大家对线程的创建方式有了更深的了解了。

实现任务代码的方式

理解了创建线程的本质方式,还是有必要来了解下实现任务代码的方式,毕竟这才是实现具体的业务逻辑的方式,下面列举了几种场景的实现任务代码的方式。

1、创建Thread匿名内部类并重写run方法执行任务逻辑

public class MyThread {
    public static void main(String[] args) {
        Thread t = new Thread(){
            @Override
            public void run() {
                System.out.println("execute MyThread job");
            }
        };
        t.start();
    }
}

执行t.start()该行代码就会去执行Thread类的run()方法中的代码。

2、创建Thread子类并重写run方法执行任务逻辑

如要执行自己的代码,则需要重写new一个Thread的子类,然后重写run()方法,如上也可以将上面匿名内部类的写法改成下面更直观的写法:

public class MyThread2 extends Thread{
    @Override
    public void run() {
        System.out.printf("execute MyThread2 job");
    }
    public static void main(String[] args) {
        Thread t = new MyThread2();
        t.start();
    }
}

可见,两种写法都是创建Thread的子类并重写run方法。

3、创建Runnable匿名内部类并重写run方法

在Thread的构造函数中,有一个构造函数接受一个Runnable对象,当Runnable对象不为空的时候,将会执行Runnable对象的run方法。

public class MyThread3 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("execute MyThread3 job");
            }
        });
        t.start();
    }
}

线程是一个对象,线程要运行的代码也是一个对象,封装在Runnable对象里面,更符合面向对象的思维。

4、创建Runnable子类并重写run方法执行任务逻辑

也可以将上面匿名内部类的写法改成下面更直观的写法:

public class MyThread4 implements Runnable {
    @Override
    public void run() {
        System.out.println("execute MyThread3 job");
    }
    public static void main(String[] args) {
        MyThread4 r = new MyThread4();
        Thread t = new Thread(r);
        t.start();
    }
}

可见,两种方式都是创建Runnable对象并传递到Thread构造函数。

正确停止线程

上面的例子中,我们只管线程的创建,却不需要用代码显示的停止线程,这又是为什么?如何停止线程?代码执行完会自动销毁线程吗?如何正确停止线程?Thread类中有没有方法获取线程启动到销毁整个过程的运行状态?答案是有的。通过Thread类的getState()方法我们可以获取线程的运行状态。

    /**
     * Returns the state of this thread.
     * This method is designed for use in monitoring of the system state,
     * not for synchronization control.
     *
     * @return this thread's state.
     * @since 1.5
     */
    public State getState() {
        // get current thread state
        return sun.misc.VM.toThreadState(threadStatus);
    }

我们先通过一个例子来观察线程的运行过程的状态变化。

public class MyThread {
    public static void main(String[] args) {
        Thread t = new Thread(){
            @Override
            public void run() {
                System.out.println("execute MyThread job,thread state:"+getState());
            }
        };
        System.out.println("before start thread,thread state:"+ t.getState());
        t.start();
        try {
            //让主线程睡眠1秒,等待子线程t先执行完
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("after start thread,thread state:"+ t.getState());
    }
}

运行结果

before start thread,thread state:NEW
execute MyThread job,thread state:RUNNABLE
after start thread,thread state:TERMINATED

从运行结果可以看出,程序运行完或者说run()方法运行完成后,线程进入TERMINATED状态,由此我们可以得出结论:run()方法执行完线程进入停止状态,这是线程自然终止的过程。关于线程的运行状态,我们将在后续的文章中学习,在此我们主要了解线程的终止后的状态。Thread类中有start()方法启动线程,那肯定有停止线程的相关方法,我们也可以通过Thread类提供的一些方法来终止线程。

在这里插入图片描述

从上图可以看出,画横线的方法都被废弃了,其中包括stop()方法。

/**
     * Forces the thread to stop executing.
     * ...
     * @deprecated This method is inherently unsafe.  Stopping a thread with
     *       Thread.stop causes it to unlock all of the monitors that it
     *       has locked (as a natural consequence of the unchecked
     *       <code>ThreadDeath</code> exception propagating up the stack).  If
     *       any of the objects previously protected by these monitors were in
     *       an inconsistent state, the damaged objects become visible to
     *       other threads, potentially resulting in arbitrary behavior.  Many
     *       uses of <code>stop</code> should be replaced by code that simply
     *       modifies some variable to indicate that the target thread should
     *       stop running.  The target thread should check this variable
     *       regularly, and return from its run method in an orderly fashion
     *       if the variable indicates that it is to stop running.  If the
     *       target thread waits for long periods (on a condition variable,
     *       for example), the <code>interrupt</code> method should be used to
     *       interrupt the wait.
     *       For more information, see
     *       <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
     *       are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
     */
    @Deprecated
    public final void stop() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            checkAccess();
            if (this != Thread.currentThread()) {
                security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
            }
        }
        // A zero status value corresponds to "NEW", it can't change to
        // not-NEW because we hold the lock.
        if (threadStatus != 0) {
            resume(); // Wake up thread if it was suspended; no-op otherwise
        }

        // The VM can handle all thread states
        stop0(new ThreadDeath());
    }

从stop()方法的注释可以看出,其被废弃的主要原因是简单粗暴的终止线程,让程序执行结果具有不确定性,固有的天生的不安全。注释中也提到停止线程的另一个方法Thread.suspend 同样被废弃。

/**
 * Suspends this thread.
 ...
 * @deprecated   This method has been deprecated, as it is
 *   inherently deadlock-prone.  If the target thread holds a lock on the
 *   monitor protecting a critical system resource when it is suspended, no
 *   thread can access this resource until the target thread is resumed. If
 *   the thread that would resume the target thread attempts to lock this
 *   monitor prior to calling <code>resume</code>, deadlock results.  Such
 *   deadlocks typically manifest themselves as "frozen" processes.
 *   For more information, see
 *   <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
 *   are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
 */
@Deprecated
public final void suspend() {
    checkAccess();
    suspend0();
}

从suspend()方法的注释可以看出,其被废弃的主要原因是固有的天生的容易造成死锁。由于停止线程涉及到锁、监视器、共享资源等知识,在此不深入这些内容,我们先从官方注释来理解其被废弃的原因即可,等后面学习到这块的知识后再回过头来理解就更容易了。

一眼就看出是停止线程的stop()方法,suspend()方法,却不是正确停止线程的方法,那么哪个方法才是正确停止线程的方法?先说结论,是interrupt()方法。通常通过interrupt()方法来终止处于阻塞状态或等待状态的线程。

/**
 * Interrupts this thread.
 *
 * <p> Unless the current thread is interrupting itself, which is
 * always permitted, the {@link #checkAccess() checkAccess} method
 * of this thread is invoked, which may cause a {@link
 * SecurityException} to be thrown.
 *
 * <p> If this thread is blocked in an invocation of the {@link
 * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
 * Object#wait(long, int) wait(long, int)} methods of the {@link Object}
 * class, or of the {@link #join()}, {@link #join(long)}, {@link
 * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
 * methods of this class, then its interrupt status will be cleared and it
 * will receive an {@link InterruptedException}.
 *
 * <p> If this thread is blocked in an I/O operation upon an {@link
 * java.nio.channels.InterruptibleChannel InterruptibleChannel}
 * then the channel will be closed, the thread's interrupt
 * status will be set, and the thread will receive a {@link
 * java.nio.channels.ClosedByInterruptException}.
 *
 * <p> If this thread is blocked in a {@link java.nio.channels.Selector}
 * then the thread's interrupt status will be set and it will return
 * immediately from the selection operation, possibly with a non-zero
 * value, just as if the selector's {@link
 * java.nio.channels.Selector#wakeup wakeup} method were invoked.
 *
 * <p> If none of the previous conditions hold then this thread's interrupt
 * status will be set. </p>
 *
 * <p> Interrupting a thread that is not alive need not have any effect.
 *
 * @throws  SecurityException
 *          if the current thread cannot modify this thread
 *
 * @revised 6.0
 * @spec JSR-51
 */
public void interrupt() {
    if (this != Thread.currentThread())
        checkAccess();

    synchronized (blockerLock) {
        Interruptible b = blocker;
        if (b != null) {
            interrupt0();           // Just to set the interrupt flag
            b.interrupt(this);
            return;
        }
    }
    interrupt0();
}

上面interrupt()的注释,主要描述了线程因为各种原因(如调用wait()方法、sleep()方法等)进入阻塞状态或等待状态时,调用interrupt()方法时线程的中断状态将被修改并抛出异常从而终止线程的运行。我们通过代码来验证这一结论。

public class InterruptThread {
    public static void main(String[] args) throws Exception{
        Thread t1 =new Thread(()-> {
            try {
                System.out.println("t1 thread sleep ");
                //子线程t1调用sleep()方法使其进入等待状态
                Thread.sleep()方法进入等待状态(3000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t1.start();

        //主线程睡眠一会等待子线程t1执行
        Thread.sleep(500L);
        System.out.println("t1 thread before interrupt state: " + t1.getState());
        System.out.println("main thread interrupt t1 thread");
        //中断子线程t1
        t1.interrupt();

        Thread.sleep(500L);
        System.out.println("t1 thread after interrupted state: " + t1.getState());
    }
}

运行结果

t1 thread sleep 
t1 thread before interrupt state: TIMED_WAITING
main thread interrupt t1 thread
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at com.demo.service.concurrent.InterruptThread.lambda$main$0(InterruptThread.java:10)
	at java.lang.Thread.run(Thread.java:748)
t1 thread after interrupted state: TERMINATED

上面的运行结果印证了上述结论,线程进入TIMED_WAITING等待状态后,调用interrupt()会抛出异常并终止线程的运行。停止线程的方式还有其他方式,后面我们学到相关知识后再回过来补充。

总结

本文从官方jdk源码的角度去分析理解创建线程的本质方式和正确停止线程的方式,希望能他大家带来更深刻的理解而不是单纯的死记硬背。

《C++并发编程实战》第二版:现代C++并发编程演进与实战指南 并发编程是现代软件开发的核心技术之一,它允许多个任务同时执行,从而提升系统性能和资源利用率。其原理基于多线程、进程或协程的协同工作,通过同步机制确保数据一致性。在C++领域,随着C++11/14/17/20标准的演进,并发编程从基础的线程管理发展到内存模型、无锁数据结构和并行算法等高级范式。这些技术价值在于能够构建高性能、高响应的服务器、游戏引擎和实时数据处理系统。本书第二版深入探讨了C++内存模型、原子操作、并行算法执行策略以及协程等关键主题,特别是通过对比不同内存顺序(如memory_order_acq 阅读详情

相关推荐

Java并发编程:CountDownLatch核心原理、使用场景与实战解析

在Java多线程编程中,线程同步与协作是构建高并发、高性能应用的核心基础。其原理通常基于共享状态与等待/通知机制,通过协调多个线程的执行顺序来确保数据一致性与任务有序性。这一技术价值在于能够显著提升系统吞吐量、降低响应延迟,并优化资源利用率。常见的应用场景包括服务启动依赖检查、并行任务执行与结果汇总、批量数据处理等。本文聚焦于Java并发包中的CountDownLatch工具,深入解析其基于AQS(AbstractQueuedSynchronizer)的底层实现,并通过实战代码演示其在**多线程同步**与*

weixin_30591551的博客 404

线程的创建与终止

一、线程的创建 新增的线程可以通过调用pthread_create函数创建。 1、函数原型 int pthread_create 2、参数 (1)thread:返回线程ID; (2)attr:设置线程的属性,attr为NULL表示使用默认属性; (3)start_routine:是个函数地址,线程启动后要执行的函数; (4)arg:传给线程启动函数的参数。 3、返回值 成功返回0;失败返回错误码。 4、错误检查 (1)传统的一些函数是,成功返回0,失败返回-1,并且对全局变量errno赋值以指示错误。 (

qq_68456719的博客 1063

RTX5 | 线程管理实战 - 精准控制线程生命周期与资源回收

本文深入探讨了RTX5线程管理的实战技巧,重点解析了osThreadExit在精准控制线程生命周期与资源回收中的关键作用。通过对比Detached和Joinable两种线程属性,结合实际项目案例,详细介绍了如何根据任务需求选择合适的线程退出策略,有效避免内存泄漏问题,提升嵌入式系统性能。

weixin_34116482的博客 209

java并发编程第一课 线程的创建、停止和状态变更

开篇词: 由点及面,搭建你的 Java 并发知识网 你好,欢迎学习《Java 并发编程核心 78 讲》,我是讲师星星,一线互联网公司资深研发工程师,参与过集团内多个重点项目的设计与开发。 扎实的理论基础,宝贵的并发实践经验 工作期间,因为业务需要,我所开发和负责的场景大多数都是大流量和高并发的,其中有很多是对 Java 并发知识的实际应用。学习如逆旅,从小白成长为并发大神,困难重重,既然不能逃避,那么唯有改变对它的态度。 从一开始面对线程池导致的 OOM 问题的不知所措

fegus的博客 676

RT-Thread线程核心解析:从创建、调度到实战设计

在嵌入式实时操作系统中,多线程是实现复杂任务并发执行的基础。其核心原理是通过时间片轮转和优先级抢占调度,让单个CPU能够高效处理多个任务。线程作为独立的执行单元,拥有自己的代码、控制块和栈空间,通过上下文切换保存和恢复运行状态。这种机制对于满足嵌入式系统实时性要求至关重要,广泛应用于工业控制、物联网设备、消费电子等领域。以RT-Thread为例,线程管理不仅涉及静态与动态创建的资源分配策略,还需精心设计优先级与栈大小,以避免优先级反转和栈溢出等常见问题。理解线程的本质与调度机制,是构建可靠嵌入式应用架构的关

weixin_30394669的博客 425

C++cgal库配置+VS2017

Cgal几何图形库在VS2017上的下载、安装与配置。想要一口气下载完所有安装配件的,可以去文章末尾的链接。httpshttpshttpshttpshttpshttpshttpshttpshttpshttpshttpshttpshttpshttpshttps。

dsn3S的博客 1488

并发编程原理与实战(三)一步步剖析线程返回值

本文一步步分析了线程返回值的来龙去脉,总结下过程:1、Thread类只接收Runnable类型的任务但是没有返回值,Callable类型的任务有返回值但是不能往Thread类里面传,所以引入了Future接口对任务返回结果进行表示。2、Future接口更多的是对异步任务执行结果的抽象,并没有提交给线程执行的相关方法,所以还是不能“往Thread类的构造函数里面扔”,所以又引入了FutureTask类,一个FutureTask类型的任务同时具备提交到线程运行的能力和获取返回结果的能力。

真战 888

MIT 18.03 微分方程 ODE 学习笔记分享——目录

从B站上看到了MIT 微分方程的课程,觉得老爷子讲的真好! 其实微分方程对于工科来说相当重要,但是很多学习也仅把他放在高数里作为单独的一个章节来讲,这是远远不够的。所以对于同学们来说 ,一定要认真听讲,做好笔记! 以下是我的个人学习比较分享。有需要的同学可以做一个参考。 注:个人认为笔记的作用是用来回想起课堂所讲的内容(细节),所以我的笔记风格为以老师讲课思路为准,板书为辅。建议刚开始听这门课的同...

weixin_40664094的博客 2625

并发编程原理与实战(八)详解并发协同利器Semaphore

本文讲解了计数信号量和二进制信号量的概念,并对创建信号量、获取和释放信号量的主要方法,以及公平性的概念进行了讲解,希望通过解读这些方法能加深对Semaphore的理解。

真战 864

Netapp FAS2750更换磁盘后不同步问题处理

netapp fas2750磁盘更换后不同步问题处理

jetliu05的博客 1256

【backtrader保姆级教学】投资组合回测

method1:探索投资组合的最有方案,使用蒙特卡洛模拟Markowitz模型。# 提取最小波动组合对应的权重, 并转换成Numpy数组。# 绘制收益-标准差的散点图,并用颜色描绘夏普比率。# 在收益-风险散点图中突出风险最小的点。:param any_day: 任意日期。# 将该点坐标显示在图中并保留四位小数。password = “替换密码”# 找到标准差最小数据的索引值。user = “替换账号”# 计算GMV投资组合收益。# 计算每项资产的夏普比率。# 设置无风险回报率为0。

weixin_38132951的博客 2315

并发编程原理与实战(十一)并发协同利器Phaser之方法详解

类别‌‌核心方法‌‌应用场景‌构造函数创建相位器实例线程注册与注销增加或者减少参与者线程同步控制线程阶段协同运行控制阶段终止控制阶段转换时的行为逻辑状态查询监控相位器的运行状态如果文章对您有帮助,不妨“帧栈”一下,关注“帧栈”公众号,第一时间获取推送文章,您的肯定将是我写作的动力!

真战 1581

DBeaver 实战:手动配置 PostgreSQL JDBC 驱动的高级技巧

本文详细介绍了在DBeaver中手动配置PostgreSQL JDBC驱动的高级技巧。针对企业内网、多版本数据库兼容等场景,从获取官方驱动文件、创建自定义驱动配置,到使用Maven坐标管理、连接参数调优及解决常见连接问题,提供了完整的实战指南,帮助开发者实现对数据库连接环境的精准掌控。

apple5的专栏 835

并发编程原理与实战(七)详解并发协同利器CyclicBarrier

本文详细讲解了循环屏障CyclicBarrier的主要方法,通过“同时对接口发起多次压测”这个例子,和用CountDownLatch实现对比,说明了循环屏障的使用。

真战 1289

从工创赛实战到开源:一个高鲁棒性智能物流视觉系统的构建与优化

本文分享了从工创赛实战中构建高鲁棒性智能物流视觉系统的完整经验。针对赛场复杂光线环境,详细阐述了摄像头选型、基于CLAHE和形态学梯度的抗干扰色环识别算法、卡尔曼滤波状态估计以及多线程串口通讯与任务调度等核心优化策略,旨在打造一个稳定可靠的视觉系统,并已将相关代码开源。

weixin_29046035的博客 316

2、机器人控制技术:阻抗/导纳控制与强化学习的融合

本文探讨了阻抗/导纳控制与强化学习在机器人控制中的融合应用。阻抗/导纳控制广泛应用于外骨骼和跟踪控制,通过改进方案提升建模误差下的鲁棒性;强化学习则为解决维度灾难、实现最优交互提供了有效途径,尤其在大输入空间、连续时间系统、冗余机器人及鲁棒控制中表现突出。结合近似器与合理奖励设计,强化学习可在无模型情况下实现高效控制。未来,两者融合有望推动更智能、更安全的机器人系统发展。

ice55的博客 299

并发编程原理与实战(四)经典并发协同方式synchronized与wait+notify详解

本文由多线程的概念引出并发协同以及对象监视器锁(synchronized)的概念,在调用wait()和notify()方法前必须先获得对象监视器锁,并讲解了synchronized的使用方法。通过两个线程交替顺序输出数字的经典题目,结合官方说明一步步分析线程如何获得锁,以及wait()和notify()的使用方法。在此我们总结出并发协同的核心思路:弄清楚并发的是什么,什么时候需要协同,谁来等待,谁来唤醒,通过这样的一个分析过程,希望能让大家深刻理解基础的并发协同的方式。

真战 1823

huggingface高速下载模型的实战代码

本文主要介绍了huggingface高速下载模型的实战代码,尤其是无法通过国内源进行下载的huggingface模型,希望能对学习大模型的同学们有所帮助。需要特别说明的是,本文的代码是完全原创的,即能够最大限度利用宽度的速度,而且还能实现断点续传。 文章目录 1. 背景 2. 实战代码

herosunly的博客 29万+

并发编程原理与实战(十)并发协同利器Phaser之概念详解

本位介绍了Phaser相位器的概念和使用场景,讲解了线程在Phaser相位器上注册与注销的概念、Phaser相位器中阶段号的概念、Phaser相位器分层的背景与作用,最后讲解了相位器监控的一些常用方法,希望通过系统的学些这些概念能加深对Phaser相位器的了解。

真战 1243

精雕软件(JDpaint) 5.5 绿色版

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

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

并发编程原理与实战(十二)并发协同利器Phaser之应用举例与总结

本文分析如何将Phaser‌运用到具体的实际场景中,并对CountDownLatch、CyclicBarrier、Semaphore、Phaser这四个多线程并发协同工具类做了对比总结。

真战 1036

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

并发编程原理与实战(六)详解并发协同利器CountDownLatch

本文分析了CountDownLatch的的主要方法和使用场景,总结了CountDownLatch的await()方法和Object中的wait()方法的一些区别。

真战 805

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

并发编程原理与实战(九)限流利器信号量的最佳实践分析

本文讲解了信号量隔离的概念,并用一个简单的例子说明用信号量来控制并发调用接口的线程数量的实现过程,然后分析了信号量在Hystrix的运用,讲解了Hystrix中的隔离策略,详细分析了Hystrix中信号量的定义方式、信号量的创建和使用。

真战 1463

并发编程原理与实战(二)Thread类关键API详解

本文对Thread类的构造函数、主要成员变量、常用成员方法进行了讲解,目的是了解线程具有哪些行为操作,进一步加深对线程的理解。

真战 1196

并发编程原理与实战(五)经典并发协同方式伪唤醒与加锁失效原理揭秘

本文通过例子详细说明了基于synchronized与wait() notify()实现并发协同时出现的伪唤醒问题,以及列举了几种常见的synchronized加锁失效的问题,希望通过论证这些问题能让大家进一步掌握synchronized与wait() notify()的应用。

真战 1018

并发编程基础:Java线程池ThreadPoolExecutor核心原理

这些参数的协同工作构成了线程池的弹性伸缩机制,例如当核心线程满载后,新任务会先进入队列,队列饱和才会触发非核心线程创建。这种精细的状态控制保证了线程池在关闭时的行为确定性,是优雅停机的基础。在当今高并发的软件系统中,线程池作为资源管理的利器,已成为Java开发者必须掌握的核心技术之一。特别值得注意的是,非核心线程在空闲超过keepAliveTime后会自动回收,这种动态调整机制有效平衡了资源利用率与响应速度。掌握这些原理后,面对高并发场景时就能像指挥家一样,优雅地协调线程资源,奏响性能最优的乐章。

lfuwql_034的博客 238

C++并发编程实战:从理论到项目,整本书测试巩固指南

并发编程是现代软件开发的核心技术之一,它通过允许多个任务同时执行来提升程序性能。其原理主要围绕线程管理、共享数据同步和内存模型展开,旨在解决数据竞争和死锁等核心挑战。掌握并发编程的技术价值在于能够构建高性能、高响应性的服务器、游戏引擎和数据处理系统。在实际应用场景中,开发者常需实现线程池、无锁队列等并发组件。本文以《C++并发编程实战》为蓝本,通过设计分层测试框架和综合项目实战,系统性地串联**线程管理**、**共享数据保护**等关键知识点,帮助开发者将理论知识转化为解决实际工程问题的能力,并规避数据竞争等

weixin_33951761的博客 492
下一篇: 并发编程原理与实战(二)Thread类关键API详解
帧栈
博客等级 码龄2年 335粉丝 120原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帧栈

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值