Reentrantlock和背后金主AQS —————— 开开开山怪

基于MATLAB的太阳能光伏电力仿真,模拟每日太阳能发电,可视化功率曲线,并通过数值积分计算总能量输出。.zip 1.版本:matlab2014a/2019b/2024b 2.附赠案例数据可直接运行。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 立即下载
1.Reentrantlock那些常用的方法
lock()方法
unlock()方法
lockInterruptibly()方法
2.等待队列图解

在这里插入图片描述

说起lock方法,其实lock() 和 unlock()相当于synchronize的左花括号和右花括号,但是当我们用到lock()的时候,需要手动的进行再合适的地方unlock()这样的话才能够释放锁,而synchronize到右花括号结束的话就释放锁。
下来我们就看看线程之间是如果争夺这个锁的。
先设一个前提,有三个线程都想要获取同一把锁进行对应的操作,Reentrantlock背后是怎样处理的

public class ReentrantLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = 7373984872572414699L;

    private final Sync sync;
    public ReentrantLock() {
    //无参的初始化默认为非公平同步
        sync = new NonfairSync();
    }
     public ReentrantLock(boolean fair) {
     //对于我们进行初始化的时候
     //Sync类继承了AQS类
     //FairSync类继承了Sync 为公平锁
     //NonfairSync继承了Sync  为非公平锁
        sync = fair ? new FairSync() : new NonfairSync();
    }
      public void lock() {
      //
        sync.lock();
    }
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
    public void unlock() {
        sync.release(1);
    }
}

其实在Reentrantlock中的代码很简单,但是不止我上边所展示的这些。
从上边的代码看。其实不管是这三个方法的哪一个方法,都离不开Sync,其实Sync是Reentrantlock的一个静态内部类。
Sync 继承了 AQS,这说明对于真正Reentrantlock可以做到同步的效果AQS这个类真是功不可没,并且成员sync也是有一定的分量。

剧透:
对于同一个锁来说,也相当于是同一个Reentrantlock对象来说,
这个对象中维持一个等待队列,确切的说是背后的AQS对象维持了一个等待队列,Reentrantlock是依靠AQS的。这个等待队列是一个双向的链表。AQS通过一个 volitile int state 来保证线程之间的同步。
先康康AQS中的主要成员。

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer
    implements java.io.Serializable {
    
    private transient volatile Node head;
    private transient volatile Node tail;
     private volatile int state;

由于AQS类继承了AOS,所以AQS也相当于拥有AOS类的成员。

public abstract class AbstractOwnableSynchronizer implements java.io.Serializable {
   
   private transient Thread exclusiveOwnerThread;
}
    

插曲 : 公平锁 和 非公平锁

我觉得例子总是让我们清晰易懂。
脑补此时有三个线程,想要获取同一个锁,如果第一个线程抢占到CPU资源,那么第一个线程会通过lock方法首先拥有锁,拥有锁体现为AQS中的int state变量会变为1.

当线程一的时间片段到了,此时线程一并没有运行到unlock方法,那就说明此时的锁没有被释放,同时也体现在AQS中的int state变量没有被更改回0.

此时线程二和线程三依次运行起来,检查AQS中int state的值为1,说明锁被其他线程所持有,那么线程二和三则被加入到AQS维持的等待队列中。

1.公平锁:
如果此时线程一释放了锁,其实释放锁的同时会唤醒等待队列中最老的线程(此时为线程二),此时线程二依旧在等待队列中保存,只有线程二获取到锁,才会从等待队列中删除。
那么此时如果线程一和线程二同时竞争CPU资源,线程一竞争到了cpu资源,又开始获取锁,对于公平锁来说,那当然要维持公平了,所以线程一在获取锁的过程中,程序先检查等待队列中是否有线程正在等待,如果有的话,先看最老的等待线程是否和当前想要获取锁的线程是同一个线程,很明显此时最老线程为线程二,当前线程为线程一,所以会直接将当前的线程一阻塞起来并加入到等待队列中(加入到线程三的后面)。
线程二此时因为已经被唤醒了,只是正等待竞争到cpu然后获取锁,在获取锁后就将自己在等待队列中删除。
公平锁相当于,只要是在等待队列中的线程都有获取锁的机会。
优点:所有的线程都能够得到资源,不会产生饥饿的状态
缺点:吞吐量会下降,因为不管有几个线程进行竞争,只要不是等待队列中的等待的线程,先加入到等待队列中,只允许按照申请锁的顺序进行获取锁,cpu唤醒等待线程的开销会增大

2.非公平锁:
看完上边公平锁,非公平锁也很好理解,当线程一再次想要获取锁的时候,程序不管等待队列的是否还有其他从未获取过锁的线程在等待,只要线程一再次抢占到cpu资源可以再次拥有锁。
此时就必得是谁能先抢占CPU的资源。这样就可能导致等待中的某些线程一直处于等待的状态,甚至没有获得锁的机会。
优点:可以减少CPU唤醒线程的开销,
缺点:会导致有些等待线程饿死的现象,申请的早,但迟迟没有机会获取锁。

下来我们就具体说说这个lock的方法和unlock方法(我拿非公平锁做例子)
先看这个一层层的调用关系,你们可以对照源码比较方便,同时也是展示有用的代码,其他就不说了。

一.lock():

public class ReentrantLock implements Lock, java.io.Serializable { 
    public void lock() {
        sync.lock();
    }
      

这边的sync.lock()调用的是NonfairSync中的lock()方法;NonfairSync是Reentrantlock的静态内部类。

static final class NonfairSync extends Sync {
	final void lock() {
	//采用CAS操作将AQS中的state变量进行修改为1,表明当前线程已经拥有锁
            if (compareAndSetState(0, 1))
        //将AQS中的exclusiveOwnerThread变量设置为当前的线程
                setExclusiveOwnerThread(Thread.currentThread());
            else
            //对于如果其他线程持有锁,而其当前的线程也想要获取锁的话
            //当前线程会运行到这里,因为AQS中的state状态已经被其他持有锁
            //的线程从0修改为1,当前线程只能去尝试获取锁。
                acquire(1);
        }
   }
acquire();
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer
    implements java.io.Serializable {

    public final void acquire(int arg) {
   //tryAcquire方法是由NonfairSync类进行实现的。
   //tryAcquire方法中进行AQS中状态的获取,
   // 如果是0,表明现在没有任何线程持有锁,那么会将AQS中的状态改为1.并将AQS中的exclusiveOwnerThread设为当前执行的线程。并且返回true。  
   //如果是1,表明已经有线程持有锁了,那判断AQS中的exclusiveOwnerThread是否是当前线程,如果是当前线程,那此时表明当前线程重入,那么只是将AQS的状态加1,返回true
   //如果不是当前运行的线程,那说明当前线程想要获取锁,而此时锁已经被占有那只能返回false。表明当前线程获取锁失败。
        if (!tryAcquire(arg) &&//当前线程试图想要通过tryAcquire(arg)获取锁
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
             selfInterrupt();
   //当tryAcquire(arg)返回值为false时,有必要进行acquireQueued()的判断
   //返回false说明获取锁失败,那么就要对此种情况进行处理。
   //addWaiter(Node.EXCLUSIVE)方法就是将当前线程形成一个Node节点放入AQS维持等待队列中,返回值为Node。
   //在加入到队列的过程中,如果队列为空,表示AQS中的head 和tail的值为null,AQS也是通过head和tail来维持这个等待队列的。
   //同时也说明当前线程是第一个加入到等待队列中的,等待队列是一个带头节点的双向链表,
   //那么此时会先生成一个空的node作为头节点,然后再将当前线程所形成的节点加入头节点之后,形成这个等待队列.
   // acquireQueued()方法将当前的Node节点中的线程,也就是当前线程阻塞起来。
   //具体的过程看下面两个方法具体过程
     
    }
}
Node节点主要成员
static final class Node {
    static final int CANCELLED =  1;
    static final int SIGNAL    = -1;
    static final int CONDITION = -2;
    static final int PROPAGATE = -3;    
    volatile int waitStatus;
    volatile Node prev;
    volatile Node next;
    volatile Thread thread;
    Node nextWaiter;
}
acquireQueued()
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer
    implements java.io.Serializable {

     final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
         //p为线程所包装的节点的前驱节点,因为在addwaiter的方法中已经将当前线程
         //包装为一个Node几点并且加入到等待队列中了
         //p可能为空的头节点,也可能为已经加入到等待队列中的其他线程所构成的节点
                final Node p = node.predecessor();
         //如果为头节点,表明当前线程是所构成的节点是第一个加入到等待队列中的,此时由机会去获取锁,
         //为什么这么说呢,跟排队一样当然是第一个排队的人最可能先得到服务
         //这里也一样,如果此时是等待队列中的第一个,那么有机会进行tryAcquire(arg),也就是锁的获取操作,如果成功获取锁,那就说明当前线程所形成的节点不用在等待队里中了,那么会进行一次队列删除操作。
      
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
  //当当前线程获取锁没有成功时,就会进入到下面的判断,
  // shouldParkAfterFailedAcquire(p, node)这个方法主要是来判断当前线程是否具备阻塞的条件,
  //新节点刚加入的时候是不满足阻塞条件的,那么此时会再次循环
  //此时就会跑到上面的if判断,相当于又给了线程一个次获得锁的机会,当for循环第二次到 shouldParkAfterFailedAcquire(p, node)时候,此时当前线程就满足了阻塞条件,
  //因为第一次的时候shouldParkAfterFailedAcquire(p, node),将新加入的节点的前驱节点的状态改为SIGNAL,返回false
  //第二次的时候检查当前节点节点的前驱节点状态已经为SIGNAL,所以返回true。
  //只要当前节点的前驱节点的状态为SIGNAL,就表明当前线程可以进行阻塞。
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
  // parkAndCheckInterrupt()方法就是当shouldParkAfterFailedAcquire(p, node)方法返回true的时候就执行,执行的内容就是将当前线程进行阻塞,如果当前线程设置类中断标志,那么当该线程被唤醒的时候返回true
 //如果没有设置中断标志,那么该线程被唤醒的时候返回false
 //并且当前线程已经形成节点在等待队列中了,就等着其他线程释放锁,在等待队里中国唤醒自己。
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
      }
}
shouldParkAfterFailedAcquire(p, node)
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer
    implements java.io.Serializable {
    
    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;//得到当前线程所在节点的前驱节点的状态,
        if (ws == Node.SIGNAL)//如果前驱节点的状态为SIGNAL(-1)状态,说明此事该线程的阻塞条件达到,
        //因为在之后在释放锁的时候会在等待队列中去唤醒头节点的的后驱节点
        //每一个等待节点都有可能变为头节点,在下图会看的更详细
        //所以当前节点的前驱节点的状态应该是SIGNAL状态,因为这样在之后能够根据它的前驱节点为SIGNAL而唤醒当前节点。
           return true;
        if (ws > 0) {//ws大于0表明前驱节点的状态为CANCELLED状态,表明为取消状态
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
         } else {
         //表示前驱节点为状态为0;

         //因为等待队列中的最后一个节点状态始终为0;
         //所以对新加入到等待队列中的节点来说它的前驱节点为当前队列中的最后一个节点
         //对于新加入的节点首次进入shouldParkAfterFailedAcquire方法
         //首先通过下面的这个方法将前驱节点的状态设置为SIGNAL状态。
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

二.Unlock方法()

 public void unlock() {
        sync.release(1);
    }
release(int)
 public final boolean release(int arg) {
        if (tryRelease(arg)) {//进行锁的释放,更改AQS中的state,和拥有锁的线程
            Node h = head;
            //此时的head就是等待队列的头节点
            //每次当一个线程释放自己有的锁的时候,
            //总是唤醒该锁等待队列中那个最早等待的,也就是头节点的后驱节点
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

/对于释放锁来说,如果一个线程产生了重入锁的情况那么
下面方法的getstate就不太是1. 可能会是2,3,4…

tryRelease(int)
protected final boolean tryRelease(int releases) {
//getstate得到AQS中的state的值,如果某一线程只获得过一次锁,那么此时该线程想要释放锁的话c = 1 -1 = 0;
//如果之前某一线程产生了重入锁的情况,那么此时getstate不再是1,
//所以对于重入锁的情况来说,现线程重入锁几次,就要释放锁几次,不然在那些等待队列中的线程是无法被唤醒的
//当某一线程只获得过一次锁,那么该线程此时释放锁的的话,c = 0

            int c = getState() - releases;
            
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
                //将AQS中将保存之前持有锁的线程的变量赋值为null。
            }
            //并且将AQS的state改为c的值
            setState(c);
            return free;
        }
unparkSuccessor(Node)
private void unparkSuccessor(Node node) {
//参数为头节点

        int ws = node.waitStatus;
        if (ws < 0)//表示头节点的状态为SIGNAL,将头节点的状态改为0
            compareAndSetWaitStatus(node, ws, 0);
            Node s = node.next;//得到头节点的后驱节点
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)//当头节点有后驱节点的时候,那就唤醒后驱节点中的线程
            LockSupport.unpark(s.thread);
    }

三. lockInterruptibly()

对于lockInterruptibly和lock来说不一样的一点在于lockInterruptibly将lock调用过程的的acquireQueued()方法换成了doAcquireInterruptibly方法。

采用lockInterruptibly方法进行获取锁,表明的是可以处理中断,意思很简单,就是两个线程都想要获取同一个锁,另外一个线程获取了锁,而当前的线程由于没有获取锁而加入到了等待队列,但是如果当前的线程被别的线程设置了Thread.interrupt。
那么此时当前被唤醒的性质就不是说由于某一个线程释放锁而被唤醒,而是因为中断被唤醒,所以在 doAcquireInterruptibly(int arg)方法中if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())成立之后,
那么此时这个线程被唤醒后就直接
throw new InterruptedException();由外部处理,说明当前线程放弃了获取锁。

   private void doAcquireInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
        //当由于中断唤醒,则直接抛出异常
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

应用例子:

public class Interrupt implements Runnable{
   private static final Lock lock = new ReentrantLock();
   private volatile int selected;
 
   public Interrupt(int select) {
        this.selected = select;
   }
   public void run() { 
        if(selected == 0) {
           try { 
    		lock.lockInterruptibly();
   	        for(int i = 0; i < 1000; i++) {
                } 
   		lock.unlock();     
           }catch (InterruptedException e) {
           	System.out.println("线程一说:我不想等了");
           }
        }else if(selected == 1){
           try {
               lock.lockInterruptibly();
               Thread.sleep(1000);
               lock.unlock();
               ystem.out.println("线程二说: 锁我用完了");
           } catch (InterruptedException e) {
           }

   }
       
}

  
public class Test {
 public static void main(String[] args) {
   Thread one = new Thread(new Interrupt(0));
   Thread two = new Thread(new Interrupt(1));
   two.start();
   one.start();  
   one.interrupt();

在这里插入图片描述

2.等待队列的图解

在这里插入图片描述
在这里插入图片描述

【电力负荷预测】项目介绍 MATLAB实现基于BO-Transformer-LSTM贝叶斯优化算法(BO)优化Transformer-LSTM组合模型进行居民用户多步电力负荷预测(含模型描述及部分示例 内容概要:本文介绍了一个基于BO-Transformer-LSTM的组合模型,用于实现居民用户多步电力负荷预测的完整项目实例。该模型融合Transformer的全局注意力机制与LSTM的局部时序记忆能力,构建能够捕捉长时依赖与周期性特征的深度学习架构,并引入贝叶斯优化(BO)自动搜索最优超参数组合,提升预测精度与训练效率。项目涵盖从原始数据清洗、特征工程、滑动窗口样本构建、模型设计到超参数优化、反归一化及多步误差评估的全流程,强调时间顺序划分以防止信息泄露,并通过周期编码、外生变量融合等方式增强数据表达能力。文中提供了详细的MATLAB代码示例,包括数据预处理、网络搭建、贝叶斯优化配置和预测结果评估等关键步骤。 适合人群:具备一定机器学习和时间序列分析基础,熟悉MATLAB编程环境,从事电力系统预测、智能电网、负荷管理等相关领域的研究人员、工程师及研究生。 使用场景及目标:①应用于居民级或多用户聚合负荷的短期至中期多步预测(如未来24小时);②服务于配电系统运行调度、需求响应基线设定、家庭能源管理系统优化、分布式能源协调控制等实际工程场景;③为科研提供可复现的深度学习+贝叶斯优化的技术路线参考。 阅读建议:此资源以实际项目为导向,建议读者结合提供的代码逐步实现并调试模型,重点关注数据质量控制、时间特征编码、组合网络结构设计与贝叶斯优化稳定性之间的协同关系,在实践中深入理解多步预测中的误差累积机制与超参数敏感性问题。 立即下载

相关推荐

国央企创新负责人如何通过平台实现科研成果的快速识别与转化?.docx

科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。

Java并发之谈谈对AQS的理解

一、写在前面 这篇文章,我们来聊聊面试的时候比较有杀伤力的一个问题:聊聊你对AQS的理解? 之前有同学反馈,去互联网公司面试,面试官聊到并发时就问到了这个问题。当时那位同学内心估计受到了一万点伤害。。。 因为首先,很多人还真的连AQS是什么都不知道,可能听都没听说过。或者有的人听说过AQS这个名词,但是可能连具体全称怎么拼写都不知道。 更有甚者,可能会说:AQS?是不是一种思想?我们平时开...

刘成 1919

PotPlayer自用皮肤

自用 PotPlayer 皮肤,仅微调了字体大小与颜色,是按个人习惯调整,未做适配性调整。

ReentrantLock到AQS

ReentrantLock到AQS 写在前面 上一篇讲了Synchronized的原理,这篇讲一下另一个锁ReentrantLock和它的基石AQS。 Java中的大部分同步类(Lock、Semaphore、ReentrantLock等)都是基于AbstractQueuedSynchronizer(简称为AQS)实现的。AQS是一种提供了原子式管理同步状态、阻塞和唤醒线程功能以及队列模型的简单框架。本文会从应用层逐渐深入到原理层,并通过ReentrantLock的基本特性和ReentrantLock与AQS

你的BoyZ的博客 308

2-shell及常用命令-续.pdf

2-shell及常用命令-续.pdf

【硬件开发】振铃

如果是开关管的振铃,那么桥臂的SW处产生的振铃会窜入驱动电路,造成的结果就是驱动电路和上桥臂下桥臂之间的SW节点都会有振铃现象。如果是驱动电路的振铃,那么MCU的输出引脚还是正常的PWM,但是到了MOS管两侧就变成带有振铃的PWM波形了。开关振铃产生的原因是MOS管上面的寄生电感当开关管打开时为了保持电流不变感应出的电压会对电源和地产生冲击。开关管的驱动线上的寄生电容和寄生电感导致的振铃为驱动电路振铃。开关管上的寄生电容和寄生电感导致的振铃为开关节点振铃。、电感等元件的存在,导致电路中的电压和。

weixin_62546664的博客 1827

一文彻底搞懂ReentrantLock原理【基于AQS的公平锁+非公平锁】

🍀 JVM已经帮我们内置了synchronized关键字来实现同步,为什么还要引入Lock呢? 首先需要明白synchronized是JVM层面的锁,Lock是API层面的锁,synchonized的灵活度是远不及Lock的;在JDK5时 Lock的效率是优于synchronized,在JDK6开始官方对synchronized进行了大量优化,包括锁升级、锁消除、锁粗化等,事实证明在锁竞争激烈的场景,ReentrantLock还是优于synchronized,但是synchronized还有增长空间,官方

Kevinnsm的博客 1263

光电振荡器(OEO):从原理到应用,解锁高频微波信号新纪元

本文深入解析了光电振荡器(OEO)的核心原理与前沿应用。OEO通过巧妙的光-电-光转换机制,利用光学谐振腔产生高频、高纯度、低相位噪声的微波信号,有效突破了传统电子电路的频率瓶颈。文章详细拆解了其工作流程,并探讨了在雷达系统、高速光通信及精密测量等领域的硬核应用价值。

weixin_29231027的博客 365

趣谈ReentrantLock,看完直呼通俗易懂

前言 自己开的坑,跪着也要填完,欢迎来到Java并发编程系列第五篇ReentrantLock,文章风格依然是图文并茂,通俗易懂,本文带读者们深入理解ReentrantLock设计思想。 如果读过阿星写的前篇万字长文 | 16张图解开AbstractQueuedSynchronizer,本篇的效果拉满,未读过也没关系,依然能get到ReentrantLock原理。 认识下ReentrantLock 阿星先带读者们和ReentrantLock见个面,简单的认识下什么是ReentrantLock。 Reentra

程序猿阿星 9124

别再混淆了!一张图看懂SAP特殊采购类30/40/70/80的区别与选型指南

本文深度解析SAP特殊采购类30/40/70/80的核心逻辑与业务影响,通过对比框架和真实案例帮助用户掌握其适用边界。重点介绍委外加工(类型30)、工厂间转移(类型40/70)及计划与执行分离(类型80)的配置要点与常见问题,提供选型决策树和实施检查清单,助力企业优化供应链管理。

weixin_26938645的博客 451

Visio 2013 Professional密钥安装激活全攻略:版本匹配与故障排查

产品密钥是软件授权体系中的核心凭证,用于验证用户对软件的使用权限。在微软Office产品线中,Visio 2013 Professional采用25位字符的密钥机制,通过联网或电话方式完成激活。正确使用密钥不仅能确保软件功能完整,还能避免因授权问题导致的工作中断。对于企业IT运维和个人用户而言,掌握密钥类型辨析、安装包匹配规则以及激活失败排查方法,是保障老版本软件稳定运行的关键。本文围绕Visio 2013 Professional,详细讲解密钥输入、激活流程及常见错误代码处理,帮助读者高效完成部署与维护。

weixin_28487433的博客 330

Reentrantlock和其搭档Condition —————— 开开开山怪

这篇博客具体来说说Condition,但同时也离不开Reentrantlock,因为我们知道对于synchronize来说,是由Object类配合其进行使用,那么对于Reentrantlock来说则采用的Condition和其进行配合,但不同的是对于一个synchronize只拥有一个阻塞队列,就是我们平时new 一个Object对象,采用Object对象或者是一个Object类作为Synchro...

String_guai 301

因果强化学习:优化决策策略的因果方法

1. 背景介绍 1.1 传统强化学习的局限性 强化学习(Reinforcement Learning, RL)是一种通过与环境交互来学习最优决策策略的方法。然而,传统强化学习方法在面对复杂、动态和不确定的现实世界问题时,往往存在以下局限性: 数据效率低:传统强化学习方法

AI天才研究院 658

深度解析ReentrantLock和AQS

一、什么是AQS? AQS: AbstractQueuedSynchronizer,队列同步器,它是构建锁或者其他同步组件的基础框架,它包含了state变量、加锁线程、等待队列等并发中的核心组件。 二、必备知识点: 该图片来源石衫老师公众号 AQS使用一个int类型的成员变量state来表示同步状态,state > 0表示获取锁,state == 0表示无锁状态 AQS使用一个内部变量记...

LJJZJ的博客 485

Cadence OrCAD Capture CIS元器件管理时ERROR(ORCIS-6454): Temporary part number tracking is turned on报错的解决方法

使用Part manager对工程的元器件进行批量管理时,出现如下图所示的ERROR(ORCIS-6454): Temporary part number tracking is turned on报错其解决方法如下。

fydar的博客 3501

华为OD机考双机位C卷 - 斗地主之顺子 (Java & Python& JS & C/C++ & GO )

华为OD机考双机位C卷 - 斗地主之顺子(OD上机考试双机位C卷)。提供在线OJ刷题。Java、C++、Python、GO语言、C语言、JavaScript题解,并提供完整思路讲解。

算法大师! 9692

Java 并发编程(下)线程池、JUC、AQS、ReentrantLock源码

七、共享模型之工具 1、线程池 池化技术相比大家已经屡见不鲜了,线程池、数据库连接池、Http 连接池等等都是对这个思想的应用。池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率。 线程池提供了一种限制和管理资源(包括执行一个任务)。 每个线程池还维护一些基本统计信息,例如已完成任务的数量。 这里借用《Java 并发编程的艺术》提到的来说一下使用线程池的好处: 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立

qq_43744488的博客 324

用 PERFORM ... ON COMMIT / ON ROLLBACK 把收尾工作做干净:从 SAP LUW 到 Update Task 的事务钩子实践

ABAP事务钩子机制解析 本文深入探讨SAP ABAP开发中的事务边界管理问题,重点分析PERFORM ... ON COMMIT/ROLLBACK机制: 事务分层:区分Database LUW(数据库提交)和SAP LUW(业务逻辑单元),后者通过COMMIT WORK触发多种收尾动作 钩子机制:PERFORM...ON COMMIT将子程序注册为事务结束回调,在提交/回滚时执行清理工作而非业务更新 执行顺序:钩子程序先于Update Task执行,仍保留当前会话内存上下文 现代实践:建议将FORM仅作为

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 3993

本地缓存-loadingCache

本地缓存 get方法: V get(K key, int hash, CacheLoader<? super K, V> loader) throws ExecutionException { Preconditions.checkNotNull(key); Preconditions.checkNotNull(loader); Object var15; try { //c

String_guai 1万+

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

ArrayBlockingQueue 实现多线程安全 —————— 开开开山怪

我们都知道在使用线程池的时候我们需要选择相应的阻塞队列,当核心线程池的线程处于忙的状态,那需要将新的任务加入到阻塞队列中。 一.ArrayBlockingQueue 二.LinkedBlockingQueue ...

String_guai 5345

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

LinkedBlockingQueue多线程安全的保障 —————— 开开开山怪

LinkedBlockingQueue多线程安全的保障

String_guai 4370

怀旧版电脑GBC模拟器

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

HashMap源码解析JDK1.8 —————— 开开开山怪

hashMap源码解析 导航 1.影响hashmap性能因素 key的hash实现 loadFactor的设定 2.hashMap的数据结构 3.hashmap的主要方法解析 put() get() resize() remove() containsKey()

String_guai 620

ThreadPoolExecutor线程池 —————— 开开开山怪

说起线程池大家一定都不陌生,其实在很多地方都有应用。 当我们解释为什么使用线程池的时候,我们都会说线程池可以减少线程创建的开销,节省系统的资源。 但其实线程池真正做到我们说的那样,还和我们设置的参数有关。我们都知道在我们使用线程池的时候,开头要搞很多参数。 public ThreadPoolExecutor (int corePoolSize, int maximumPoolSize,long...

String_guai 362

【FDE知识库】(1):AI 编程时代开发语言选型分析,云使用go,企业用java,算法python,底层c

AI 编程时代,开发语言选型需综合考量AI适配度、编译速度、跨平台与学习成本。Python以海量语料和即时执行成首选,适用于AI/ML与原型开发;TypeScript凭借类型系统与秒级构建,成为前端及应用层主流;Go以极速编译与统一风格,契合AI代理高效迭代需求。Rust/C++虽性能强,但编译慢、学习成本高,不适于快速试错。综合推荐:优先选Python、TypeScript、Go,兼顾效率与生态,实现最优AI协作体验。

freewebsys的专栏 520
上一篇: 采用JDBC解释java SPI机制和线程上下文类加载器 —————— 开开开山怪
下一篇: ThreadPoolExecutor线程池 —————— 开开开山怪
开开开山怪
博客等级 码龄8年 41粉丝 30原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值