[toc]
1. java1.8 中的Reference结构
在jdk1.8中,Reference位于java.lan.ref包中。
主要的类有:Reference、SoftReference、WeakReference、PhantomReference及FinalReference、和Finalizer。其中最核心的是抽象类Reference,其他的Reference都继承了这个抽象类。分别对应java的软、弱、虚引用。而强引用是系统缺省的引用关系,用等号即可表示。因此没有专门的类。另外还有一个FinalReference,这个类主要是配合Finalizer机制使用。Finalizer本身存在诸多问题,在jdk1.9中已经被替换为另外一种Cleaner机制来配合PhantomReference机制,本文暂不涉及jdk1.9中的内容仅限于jdk1.8。 还有一个关键的类是ReferenceQueue, java.lan.ref包中各类的关系如下图:
也可以通过idea提供的Diagram查看:
上述Reference总结见下表:
类名
引用类型
说明
SoftReference
软引用
堆内存不足时,垃圾回收器会回收对应引用
WeakReference
弱引用
每次垃圾回收都会回收其引用
PhantomReference
虚引用
对引用无影响,只用于获取对象被回收的通知
FinalReference
-
Java用于实现finalization的一个内部类
2. 引用与可达性
要搞懂Reference,必须要对GC的过程进行进一步的了解。 我们在前文中已经体会了jvm中定义的这些引用的具体用法。 我们知道,GC决定是否对一个对象进行回收,主要根据的是从GC ROOT 节点往下搜索,进行可达性计算。GC根据可达性结果决定是否对这些对象进行回收。可达性主要有五种,分别与这4种引用类型进行对应。
可达性类型
引用类型
说明
强可达(Strongly Reachable)
强引用(Strong Reference)
如果线程能通过强引用访问到对象,那么这个对象就是强可达的。
软可达(Soft Reachable)
软引用(Soft Reference)
如果一个对象不是强可达的,但是可以通过软引用访问到,那么这个对象就是软可达的
弱可达(Weak Reachable)
弱引用(Weak Reference)
如果一个对象不是强可达或者软可达的,但是可以通过弱引用访问到,那么这个对象就是弱可达的。
虚可达(Phantom Reachable)
虚引用(Phantom Reference)
如果一个对象不是强可达,软可达或者弱可达,并且这个对象已经finalize过了,并且有虚引用指向该对象,那么这个对象就是虚可达的。
不可达(Unreachable)
-
如果一个对象不是强可达,软可达或者弱可达,并且这个对象已经finalize过了,并且有虚引用指向该对象,那么这个对象就是虚可达的。
这是可达性的概念,我们可以通过如下示例进一步分析:
在上面这个例子中,A~D,每个对象只存在一个引用,分别是:A-强引用,B-软引用,C-弱引用,D-虚引用,所以他们的可达性为:A-强可达,B-软可达,C-弱可达,D-虚可达。因为E没有存在和GC Root的引用链,所以它是不可达。 再看如下这个更加复杂的例子:
A依然只有一个强引用,所以A是强可达
B存在两个引用,强引用和软引用,但是B可以通过强引用访问到,所以B是强可达
C只能通过弱引用访问到,所以是弱可达
D存在弱引用和虚引用,所以是弱可达
E虽然存在F的强引用,但是GC Root无法访问到它,所以它依然是不可达。
这是jvm种的5种可达性。不难看出,jvm主要是根据这些Reference的4种子类,来实现GC面对这些对象不可达的时候的不同处理办法。
3. Reference源码
3.1 核心源码
首先来看Reference源码
/**
* Abstract base class for reference objects. This class defines the
* operations common to all reference objects. Because reference objects are
* implemented in close cooperation with the garbage collector, this class may
* not be subclassed directly.
*
* @author Mark Reinhold
* @since 1.2
*/
注释说,这个抽象类是所有Reference类的基类,定义了所有Reference相关的操作,与GC紧密关联。也就是说GC会根据这些类来做一些特定的处理,直接实现其子类没有意义。什么意思,也就是说,jvm会对这个类及其子类做特殊的处理,jvmGC程序会硬编码识别SoftReference,WeakReference,PhantomReference等这些具体的类,对其reference变量进行特殊对象,才有了不同的引用类型的效果。否则,Reference与普通的类没啥区别。 Reference 主要实现两大核心功能:
实现特定的引用类型
用户可以对象被回收后得到通知 那么第一个功能在此已经可以很明白了。对于第二个功能,GC如何实现垃圾回收之后发送消息通知呢?很显然,对于GC这种性能要求很高的场景,不能采用传统的消息回调模式。万一再FullGC重消息回调阻塞或者出现性能问题,那么会导致整个JVM挂起。所以,Reference采用了另外一种方式,把被回收的Reference添加到了一个队列中。后续用户根据需要自行从queue中获取。这也解释了为啥软、弱引用提供了两调用方式,可以选择ReferenceQueue一起使用,也可以不用。但是虚引用由于只有通知消息,必须和ReferenceQuene一起使用。 现在查看Reference的源码:
public abstract class Reference {
//会被GC特殊对待
private T referent; /* Treated specially by GC */
//Reference被回收之后会被添加到这个queue
volatile ReferenceQueue queue;
/* -- Constructors -- */
//用户只需要特殊的Reference,并不关心GC状态,因此可以不需要ReferenceQueue
Reference(T referent) {
this(referent, null);
}
//构造函数中传入了queue,如果reference被GC回收,则会添加到queue中去
Reference(T referent, ReferenceQueue queue) {
this.referent = referent;
this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}
}
3.2 reference的状态
再Reference中,定义了Reference的状态:
/* A Reference instance is in one of four possible internal states:
*
* Active: Subject to special treatment by the garbage collector. Some
* time after the collector detects that the reachability of the
* referent has changed to the appropriate state, it changes the
* instance's state to either Pending or Inactive, depending upon
* whether or not the instance was registered with a queue when it was
* created. In the former case it also adds the instance to the
* pending-Reference list. Newly-created instances are Active.
*
* Pending: An element of the pending-Reference list, waiting to be
* enqueued by the Reference-handler thread. Unregistered instances
* are never in this state.
*
* Enqueued: An element of the queue with which the instance was
* registered when it was created. When an instance is removed from
* its ReferenceQueue, it is made Inactive. Unregistered instances are
* never in this state.
*
* Inactive: Nothing more to do. Once an instance becomes Inactive its
* state will never change again.
*
* The state is encoded in the queue and next fields as follows:
*
* Active: queue = ReferenceQueue with which instance is registered, or
* ReferenceQueue.NULL if it was not registered with a queue; next =
* null.
*
* Pending: queue = ReferenceQueue with which instance is registered;
* next = this
*
* Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance
* in queue, or this if at end of list.
*
* Inactive: queue = ReferenceQueue.NULL; next = this.
*
* With this scheme the collector need only examine the next field in order
* to determine whether a Reference instance requires special treatment: If
* the next field is null then the instance is active; if it is non-null,
* then the collector should treat the instance normally.
*
* To ensure that a concurrent collector can discover active Reference
* objects without interfering with application threads that may apply
* the enqueue() method to those objects, collectors should link
* discovered objects through the discovered field. The discovered
* field is also used for linking Reference objects in the pending list.
*/
大段的英文注释,实际上在学习java源代码的过程中,看懂这些注释往往比源码更加重要,有时候源码只能反应实现的具体过程,但是究竟为什么要真没实现,则在很多源码的注释中有说明。 注释中,将Reference的状态分为4种:
状态
说明
Active
刚初始化的实例是Active状态,在可达性发生变化之后,由于GC的各种特殊处理,可能会切换为Pendig或者Inactive状态,如果实例创建时注册了referenceQueue,则会切换到Pending状态,并将Reference加入到Pending-Reference队列,如果没有注册ReferenceQueue,则会切换到Inactive状态
Pending
当被加入到Penging-reference链表中的时候的状态,这些Reference等待被加入到ReferenceQueue。如果没有注册ReferenceQueue则永远不会出现这个状态
Enqueued
在ReferenceQueue队列中的Reference的状态,如果从ReferenceQueue中移除,则会进入Inactive状态
Inactive
Reference的最终状态,一旦到达Inactive状态则状态不会再发生改变
对于这四种状态,Reference的next指针和queue如下:
状态
queue
next
Active
ReferenceQueue or ReferenceQueue.NULL
null
Pending
ReferenceQueue
this
Enqueued
ReferenceQueue.ENQUEUED
队列中的下一个
Inactive
ReferenceQueue.NULL
this
状态图如下:
在上文注释中我们发现有一个Penging-reference链表,还有一个ReferenceQueue。这个链表又是来做什么的呢?常规来说,jvm应该直接将gc后的Referencce加入到ReferenceQueue中即可。但是实际上并不是如此。GC为了保证执行效率,而ReferenceQueue中的数据本身也不需要那么高的时效性,因此,在具体的代码中,jvm的GC操作只把Reference加入到了pending-Reference链表中。这是一个轻量级的操作,效率会非常高。Reference中有一个pending的成员变量,他就是这个pending-Reference链表的头节点。而discoverd 则是指向下一个节点的指针。 我们再看看Reference源码:
/* List of References waiting to be enqueued. The collector adds
* References to this list, while the Reference-handler thread removes
* them. This list is protected by the above lock object. The
* list uses the discovered field to link its elements.
*/
private static Reference pending = null;
/* When active: next element in a discovered reference list maintained by GC (or this if last)
* pending: next element in the pending list (or null if last)
* otherwise: NULL
*/
transient private Reference discovered; /* used by VM */
GC操作将Active的reference添加到了pending链表中。
3.3 ReferenceHandler
上文中说到GC只将reference添加到了Pending-Reference链表中。何时会被加入到ReferenceQueue中呢?这个过程就需要通过一个独立的线程来运行,这个线程就是ReferenceHandler。它是Reference的一个内部类,同时,为了线程安全,还有一个全局的锁:
/* Object used to synchronize with the garbage collector. The collector
* must acquire this lock at the beginning of each collection cycle. It is
* therefore critical that any code holding this lock complete as quickly
* as possible, allocate no new objects, and avoid calling user code.
*/
//GC在操作过程中需要获取reference的这个锁,与ReferenceHandler线程同步。避免造成线程不安全。
//由于GC也要用到这个锁,因此referenceHandler中的操作必须尽快完成,不生成新的对象,也不调用用户代码。避免对GC过程造成影响。
static private class Lock { }
private static Lock lock = new Lock();
/* High-priority thread to enqueue pending References
*/
private static class ReferenceHandler extends Thread {
private static void ensureClassInitialized(Class clazz) {
try {
Class.forName(clazz.getName(), true, clazz.getClassLoader());
} catch (ClassNotFoundException e) {
throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);
}
}
static {
// pre-load and initialize InterruptedException and Cleaner classes
// so that we don't get into trouble later in the run loop if there's
// memory shortage while loading/initializing them lazily.
ensureClassInitialized(InterruptedException.class);
ensureClassInitialized(Cleaner.class);
}
ReferenceHandler(ThreadGroup g, String name) {
super(g, name);
}
public void run() {
while (true) {
tryHandlePending(true);
}
}
}
线程的核心逻辑都在tryHandlePending中:
/**
* Try handle pending {@link Reference} if there is one.
* Return {@code true} as a hint that there might be another
* {@link Reference} pending or {@code false} when there are no more pending
* {@link Reference}s at the moment and the program can do some other
* useful work instead of looping.
*
* @param waitForNotify if {@code true} and there was no pending
* {@link Reference}, wait until notified from VM
* or interrupted; if {@code false}, return immediately
* when there is no pending {@link Reference}.
* @return {@code true} if there was a {@link Reference} pending and it
* was processed, or we waited for notification and either got it
* or thread was interrupted before being notified;
* {@code false} otherwise.
*/
static boolean tryHandlePending(boolean waitForNotify) {
Reference r;
Cleaner c;
try {
// 获取锁,避免与垃圾回收器同时操作
synchronized (lock) {
//判断pending-Reference链表是否有数据
if (pending != null) {
// 如果有Pending Reference,从列表中取出
r = pending;
// 'instanceof' might throw OutOfMemoryError sometimes
// so do this before un-linking 'r' from the 'pending' chain...
c = r instanceof Cleaner ? (Cleaner) r : null;
// unlink 'r' from 'pending' chain
pending = r.discovered;
r.discovered = null;
} else {
// 如果没有Pending Reference,调用wait等待
//
// wait等待锁,是可能抛出OOME的,
// 因为可能发生InterruptedException异常,然后就需要实例化这个异常对象,
// 如果此时内存不足,就可能抛出OOME,所以这里需要捕获OutOfMemoryError,
// 避免因为OOME而导致ReferenceHandler进程静默退出
// The waiting on the lock may cause an OutOfMemoryError
// because it may try to allocate exception objects.
if (waitForNotify) {
lock.wait();
}
// retry if waited
return waitForNotify;
}
}
} catch (OutOfMemoryError x) {
// Give other threads CPU time so they hopefully drop some live references
// and GC reclaims some space.
// Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
// persistently throws OOME for some time...
Thread.yield();
// retry
return true;
} catch (InterruptedException x) {
// retry
return true;
}
//调用clean方法
// Fast path for cleaners
if (c != null) {
c.clean();
return true;
}
ReferenceQueue q = r.queue;
//如果ReferenceQueue不为null 则入队
if (q != ReferenceQueue.NULL) q.enqueue(r);
return true;
}
ReferenceHandler则是在线程中的静态代码块中启动的:
static {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
Thread handler = new ReferenceHandler(tg, "Reference Handler");
/* If there were a special system-only priority greater than
* MAX_PRIORITY, it would be used here
*/
handler.setPriority(Thread.MAX_PRIORITY);
handler.setDaemon(true);
handler.start();
// provide access in SharedSecrets
SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
@Override
public boolean tryHandlePendingReference() {
return tryHandlePending(false);
}
});
}
可以看出,ReferenceHandler设置了Thread.MAX_PRIORITY 最高优先级。主要逻辑是将Pending-reference链表中的Reference添加到ReferenceUqeue。需要注意的是,为了不与GC冲突,ReferenceHandler不生成新的对象,也不调用用户代码。避免对GC过程造成影响。
4. ReferenceQueue
我们再来看看ReferenceQueue的源码。
/**
* Reference queues, to which registered reference objects are appended by the
* garbage collector after the appropriate reachability changes are detected.
*
* @author Mark Reinhold
* @since 1.2
*/
Reference queues 在注册queue之后,将GC之后的Reference放到这个队列中。其本身也是一个链表。
// 引用链表的头节点
private volatile Reference head = null;
// 引用队列长度,入队则增加1,出队则减少1
private long queueLength = 0;
为了在多线程下运行,同样也实现了锁:
// 静态内部类,作为锁对象
static private class Lock { };
/* 互斥锁,用于同步ReferenceHandler的enqueue和用户线程操作的remove和poll出队操作 */
private Lock lock = new Lock();
// 用于标识没有注册Queue
static ReferenceQueue NULL = new Null<>();
// 用于标识已经处于对应的Queue中
static ReferenceQueue ENQUEUED = new Null<>();
重点是入队的方法enqueue:
boolean enqueue(Reference r) { /* Called only by Reference class */
//获得锁
synchronized (lock) {
//判断是否需要入队
// Check that since getting the lock this reference hasn't already been
// enqueued (and even then removed)
ReferenceQueue queue = r.queue;
// 如果引用实例持有的队列为ReferenceQueue.NULL或者ReferenceQueue.ENQUEUED则入队失败返回false
if ((queue == NULL) || (queue == ENQUEUED)) {
return false;
}
assert queue == this;
//入队之后 设置为ENQUEUED 将Reference绑定只queue改为new一个新的Enqueue队列,避免循环引用
r.queue = ENQUEUED;
// 如果链表没有元素,则此引用实例直接作为头节点,否则把前一个引用实例作为下一个节点
r.next = (head == null) ? r : head;
// 当前实例更新为头节点,也就是每一个新入队的引用实例都是作为头节点,已有的引用实例会作为后继节点
head = r;
// 队列长度增加1
queueLength++;
// 特殊处理FinalReference,VM进行计数
if (r instanceof FinalReference) {
sun.misc.VM.addFinalRefCount(1);
}
lock.notifyAll();
return true;
}
}
poll 方法和reallypoll方法:
// 引用队列的poll操作,此方法必须在加锁情况下调用
private Reference reallyPoll() { /* Must hold lock */
Reference r = head;
if (r != null) {
@SuppressWarnings("unchecked")
Reference rn = r.next;
// 更新next节点为头节点,如果next节点为自身,说明已经走过一次出队,则返回null
head = (rn == r) ? null : rn;
r.queue = NULL;
// 当前头节点变更为环状队列,考虑到FinalReference尚为inactive和避免重复出队的问题
r.next = r;
// 队列长度减少1
queueLength--;
if (r instanceof FinalReference) {
sun.misc.VM.addFinalRefCount(-1);
}
return r;
}
return null;
}
// 队列的公有poll操作,主要是加锁后调用reallyPoll
public Reference poll() {
if (head == null)
return null;
synchronized (lock) {
return reallyPoll();
}
}
移除引用队列中的下一个引用元素的remove方法:
// 移除引用队列中的下一个引用元素,实际上也是依赖于reallyPoll的Object提供的阻塞机制
public Reference remove(long timeout)
throws IllegalArgumentException, InterruptedException
{
if (timeout < 0) {
throw new IllegalArgumentException("Negative timeout value");
}
synchronized (lock) {
Reference r = reallyPoll();
if (r != null) return r;
long start = (timeout == 0) ? 0 : System.nanoTime();
for (;;) {
lock.wait(timeout);
r = reallyPoll();
if (r != null) return r;
if (timeout != 0) {
long end = System.nanoTime();
timeout -= (end - start) / 1000_000;
if (timeout <= 0) return null;
start = end;
}
}
}
}
不难看出,实际上ReferenceQueue只存储了Reference链表的头节点,真正的Reference链表的所有节点是存储在Reference实例本身,通过属性 next 拼接的,ReferenceQueue提供了对Reference链表的入队、poll、remove等操作。 Reference与ReferenceQueue的完整关系如下图:
5.其他Reference源码
5.1 SoftReference
SoftReference的实现很简单,继承Reference之后,只是增加了一个时间戳。
/**
* Timestamp clock, updated by the garbage collector
*/
static private long clock;
/**
* Timestamp updated by each invocation of the get method. The VM may use
* this field when selecting soft references to be cleared, but it is not
* required to do so.
*/
private long timestamp;
在SoftReference中,有一个全局的变量clock(实际上就是java.lang.ref.SoftReference的类变量clock,其保持了最后一次GC的时间点(以毫秒为单位),即每一次GC发生时,该值均会被重新设置。 同时,java.lang.ref.SoftReference对象实例均有一个timestamp的属性,其被设置为最后一次成功通过SoftReference对象获取其引用对象时的clock的值(最后一次GC)。所以,java.lang.ref.SoftReference对象实例的timestamp属性,保持的是这个对象被访问时的最后一次GC的时间戳。 get 方法如下:
/**
* Returns this reference object's referent. If this reference object has
* been cleared, either by the program or by the garbage collector, then
* this method returns null
.
*
* @return The object to which this reference refers, or
* null
if this reference object has been cleared
*/
public T get() {
T o = super.get();
if (o != null && this.timestamp != clock)
this.timestamp = clock;
return o;
}
在每次调用get的过程中,实际上只是修改了这个时间戳的值。GC每次调用会同时修改clock和timestamp。这样就可以计算出这个softReference有多久没访问。之后决定要不要将其删除。 当GC发生时,以下两个因素影响SoftReference引用的对象是否被回收: 1、SoftReference 对象实例的timestamp有多旧; 2、内存空闲空间的大小。 具体回收过程本文不做详细展开。
5.2 WeakReference
weakReference中只有构造方法,其他方法全部继承Reference构造方法。
/**
* Creates a new weak reference that refers to the given object. The new
* reference is not registered with any queue.
*
* @param referent object the new weak reference will refer to
*/
public WeakReference(T referent) {
super(referent);
}
/**
* Creates a new weak reference that refers to the given object and is
* registered with the given queue.
*
* @param referent object the new weak reference will refer to
* @param q the queue with which the reference is to be registered,
* or null if registration is not required
*/
public WeakReference(T referent, ReferenceQueue q) {
super(referent, q);
}
5.3 PhantomReference
PhantomReference 只有一个带ReferenceQueue的构造方法。在使用的时候必须和ReferenceQueue配合一起使用。
/**
* Creates a new phantom reference that refers to the given object and
* is registered with the given queue.
*
*
It is possible to create a phantom reference with a null
* queue, but such a reference is completely useless: Its get
* method will always return null and, since it does not have a queue, it
* will never be enqueued.
*
* @param referent the object the new phantom reference will refer to
* @param q the queue with which the reference is to be registered,
* or null if registration is not required
*/
public PhantomReference(T referent, ReferenceQueue q) {
super(referent, q);
}
由此不难发现PhantomReference和weakReference在代码层面只有一个构造方法的差异。
关于Finalizer和FinaReference将在后面专门介绍。 本文参考: JDK源码阅读-Reference 阿里面试: 说说强引用、软引用、弱引用、虚引用吧
你可能感兴趣的:(java中的reference(二): jdk1.8中Reference的源码阅读)
Docker-compose编排部署Kafka伪分布式集群(为后续实验搭建基础环境)
F_Hello_World
Kafka kafka docker
本实验参照官网http://kafka.apache.org/documentation/构建,为后续了解kafka应用做环境准备。搭建环境:MAC10.15docker19.03.4docker-composeversion1.24.1jdk1.8以上(对于kafka2.x以上版本已遗弃对jdk1.7的支持)zookeeper-3.4.14(这里没使用kafka自带zk,而使用外置zk,这里zk
AI电商文生图comfyui工作流搭建定制
AI信息官
人工智能
触站AI:AI电商文生图comfyui工作流搭建定制在电商的海洋中,触站AI以其专业comfyui图像生成技术,为品牌打造个性化视觉体验,提升用户界面的舒适度和亲和力。️第一板块:comfyui图像生成系统定制️️定制化服务触站AI提供个性化的comfyui图像生成系统定制服务,确保每个企业都能拥有与其品牌特色和用户需求相匹配的图像生成系统。①品牌一致性——定制系统确保生成的图像与企业品牌风格保持
智能体群体决策在资产配置优化中的应用:提高组合效率
杭州大厂Java程序媛
DeepSeek 人工智能 ai
智能体群体决策在资产配置优化中的应用:提高组合效率关键词:智能体群体决策、资产配置优化、组合效率、优化算法摘要:本文旨在探讨智能体群体决策在资产配置优化中的应用,通过引入智能体群体决策机制,提高资产配置组合的效率。文章首先介绍了资产配置的背景和挑战,随后详细阐述了智能体群体决策的基本概念、核心理论和优化算法。在此基础上,探讨了智能体群体决策系统的设计实现方法,并分析了在实际资产配置中的应用案例。最
C++系统调用理论
李鲶鱼
c++ 开发语言 python
系统调用系统调用是应用程序请求操作系统提供服务的方式。C++程序可以使用系统调用来访问文件、管理内存、创建进程和线程等。例如,在Linux系统中,可以使用`open()`、`read()`、`write()`等系统调用进行文件库函数C++标准库和操作系统提供的库函数封装了系统调用,提供了更高级的接口。例如,``库中的`cin`和`cout`用于标准输入输出,``库中的`ifstream`和`ofs
初识Python~python基础语法
Cccc吃吃吃
python 开发语言
文章目录前言一、Python基础二、使用步骤(具体实例)1.进行简单的数学运算补充三、基本概念四、举一反三前言初识python。本章内容包含了python基础语法-常量和表达式一、Python基础可以将python作为一个计算器来使用。利用单词print,此单词意思是打印,属于python里的一个内建函数。使用print可以将一些数据打印到我们的控制台里。例如:print()括号里填写我们要打印的
每天一道算法题【蓝桥杯】【递增的三元子序列】
桦0
题解 算法 蓝桥杯 c++ leetcode 贪心算法
思路arr【0】和arr【1】分别用于更新递增序列的前两个数#define_CRT_SECURE_NO_WARNINGS1#includeusingnamespacestd;classSolution{public:boolincreasingTriplet(vector&nums){vectorarr(3);arr[0]=arr[1]=INT_MAX;for(inti=0;i
每天一道算法题【蓝桥杯】【最小路径和】
桦0
题解 算法 蓝桥杯 c++ leetcode
思路使用dp表解决问题使用DP表的思路分析在解决最小路径和问题时,动态规划(DP)是一种非常有效的方法。以下是使用DP表的详细思路分析:问题描述给定一个mxn的网格grid,其中每个单元格包含一个非负整数,表示从该单元格出发的路径成本。你需要找到从左上角(0,0)到右下角(m-1,n-1)的路径,使得路径上的成本总和最小。你每次只能向右或向下移动。DP表的定义定义一个二维数组dp,其中dp[i][
C语言【3】【文件处理】
桦0
C语言 c语言 单片机 stm32 数据结构 c# c++
函数先声明后使用C语言程序在运行的过程中是从main函数开始从上之下逐步运行的,如果函数未声明就使用就会显示函数未定义。所以一般把自定义的函数写在main函数之上导入静态库的文件C语言常用的静态库是一种非常重要的软件组件技术,它封装了数据和函数,使得程序更加模块化,便于代码的复用和管理。以下是对C语言静态库的详细介绍,包括其定义、创建和使用方法:静态库的定义静态库是C语言编程中常用的一种库文件形式
计算内容的长度的所有方法【C语言】
桦0
C语言 c语言 算法 开发语言
数组在C语言中,数组的大小是在编译时确定的,因此你可以直接使用数组的长度属性来计算数组中的元素个数。如果你有一个数组,你可以直接使用数组的声明来获取其长度。下面是一个简单的例子:在这个例子中,sizeof(myArray)会返回整个数组所占的字节数,而sizeof(myArray[0])会返回数组中单个元素所占的字节数。将整个数组的大小除以单个元素的大小,就可以得到数组中的元素个数。请注意,这种方
Java在版本控制系统(如Git)集成中的应用
墨夶
Java学习资料2 java git 开发语言
在现代软件开发中,版本控制系统(如Git)已成为团队协作和代码管理的核心工具。将Java项目与Git集成,不仅能提高开发效率,还能确保代码的可追溯性和稳定性。本文将深入探讨Java在版本控制系统(如Git)集成中的应用,通过详细的代码示例和注释,帮助您更好地理解和实践这一关键领域。初始化Git仓库与基本操作在开始一个Java项目时,首先需要初始化Git仓库,并进行基本的操作,如添加文件、提交更改等
守护你的网络堡垒:Nginx限速策略对抗DDoS攻击
墨夶
Nginx学习资料1 网络 nginx ddos
在当今互联网安全威胁日益严峻的背景下,分布式拒绝服务(DDoS)攻击已经成为许多网站和服务提供商的心头大患。这些攻击通过大量恶意流量淹没服务器资源,导致正常用户无法访问服务,给企业带来巨大的经济损失和声誉损害。而作为一款高效、稳定的Web服务器和反向代理服务器,Nginx凭借其内置的限流机制,成为抵御DDoS攻击的第一道防线。本文将深入探讨如何利用Nginx的限速功能来构建坚固的安全屏障,保护您的
侯捷 C++ 课程学习笔记:C++ 新标准11/14
『六哥』
C++ 学习 笔记 c++
演进、环境与资源C++2.0(C++11/14)新特性语言(只谈新东西),需要具备,C++语法和语意的基础C++Standard之演化C++98(1.0)、C++03(TR1,TechnicalReport1)、C++11(2.0)、C++14。C++2.0新特性包括语言和标准库两个层面,后者以headerfiles形式呈现。C++标准库的headerfiles不带副档名(.h),如#includ
【Vue】从零开始创建一个vue项目
Pota-to成长日记
vue.js 前端 javascript
一、环境准备(编程基础配置)1.安装Node.js与npm作用:Node.js是JavaScript运行环境,npm是包管理工具(类似“应用商店”),Vue项目依赖它们。步骤:访问Node.js官网,下载LTS版本(长期支持版。双击安装包,默认勾选所有选项,一路点击“Next”完成安装。验证安装:node-v#显示版本号npm-v#显示版本号配置国内镜像加速(解决下载慢问题):npmconfigs
基于pytorch的神经病网络搭建学习
停走的风
pytorch学习 学习 pytorch 人工智能
1.pycharm中code方法的使用1.1父类重写技巧操作:在需要重写的方法上右键,选择code-->Generate>OverrideMethods。作用:自动生成重写父类或接口的方法2.简单神经网络importtorchfromtorchimportnnclassyu(nn.Module):def__init__(self,*args,**kwargs)->None:super().__in
论文摘要生成器:用TextRank算法实现文献关键信息提取
Atlas Shepherd
python 算法 自然语言处理 python 信息可视化
我们基于python代码,使用PyQt5创建图形用户界面(GUI),同时支持中英文两种语言的文本论文文献关键信息提取。PyQt5:用于创建GUI应用程序。jieba:中文分词库,用于中文文本的处理。re:正则表达式模块,用于文本清理和句子分割。numpy:提供数值计算能力,如数组操作、矩阵运算等,主要用于TextRank算法的实现。importsysimportreimportjiebaimpor
基于微信小程序的文章管理系统的设计与开发(源码+lw+部署文档+讲解等)
#Takagi S#
微信小程序 notepad++ 小程序
文章目录前言项目背景介绍技术栈后端框架SSM前端框架Vue数据库MySQL(MyStructuredQueryLanguage)微信小程序具体实现截图详细视频演示系统测试系统测试目的系统功能测试系统测试结论代码参考数据库参考源码获取前言博主介绍:✌新人博主,工作经验两年+、专注于Java、小程序技术领域和毕业项目实战✌文末获取源码+数据库感兴趣的可以先收藏起来,还有大家在毕设选题,项目以及论文编写
SvelteKit 最新中文文档教程(1)—— 入门指南
前言Svelte,一个语法简洁、入门容易,面向未来的前端框架。从Svelte诞生之初,就备受开发者的喜爱,根据统计,从2019年到2024年,连续6年一直是开发者最感兴趣的前端框架No.1:Svelte以其独特的编译时优化机制著称,具有轻量级、高性能、易上手等特性,非常适合构建轻量级Web项目。为了帮助大家学习Svelte,我同时搭建了Svelte最新的中文文档站点。如果需要进阶学习,也可以入手我
Vue 中 axios 的封装详解
遇见~未来
Vue.js vue.js 前端 javascript
一、创建Axios实例/***@fileOverview封装axios请求模块*/importaxiosfrom"axios";//创建axios实例constaxiosInstance=axios.create({//设置基础请求路径baseURL:"https://api.example.com",//设置请求超时时间timeout:5000,//设置默认请求头headers:{"Conten
C语言笔记——第8章 对文件的输入输出
誓死守护发际线
C语言 c语言 linux 服务器
文章目录一、c文件的有关基本知识二、打开与关闭文件三、顺序读写数据文件四、随机读写数据文件五、文件读写的出错检测前言:在我看来,书应该越读越薄的,所以我的笔记尽量记录了每一个点,可供复习与查阅,但没有详细的解释。我的C语言的笔记是在谭浩强老师的C程序设计(第五版)的基础上总结归纳的,结合了一些我自己的见解。如果是有其他见解,也欢迎大家提出。一、c文件的有关基本知识1.什么是文件(1)程序文件包括源
C++学习笔记(十三)——指针
奕天者
C++基础学习 c++ 学习 笔记
一、指针的作用指针(Pointer)是C++中的一种特殊变量,它存储的是另一个变量的内存地址,而不是具体的值。指针有以下作用:直接操作内存地址,提高效率。动态内存分配,如new和delete。数组与字符串的操作,如遍历数组。函数参数传递,提高性能,避免数据拷贝。实现数据结构,如链表、树等。二、指针的声明、取地址和解引用(1)指针的声明作用:定义指针变量。语法:数据类型*指针变量名;示例:inta=
资深跨境人分享:5款海外仓库管理软件使用感受
在全球跨境电商高速发展的背景下,海外仓管理软件成为企业降本增效的核心工具。本文结合行业资深从业者的实战经验,对比测评ZohoBooks精英版、领星、吉客云等市场上常见的五款主流海外仓库管理软件,助您找到最适合的解决方案。一、ZohoBooks精英版作为Zoho生态系统的核心产品,ZohoBooks精英版凭借其高度集成化和全球化适配能力,非常适合出海企业使用。核心优势:智能多仓库管理:支持多仓库实时
文件上传复现
是懒羊羊吖~
android
1.PHPCMSPHPCMS头像上传功能允许用户上传ZIP压缩包,系统自动解压并删除非图片文件(如.php、.txt),利用解压后文件保留机制上传至服务器,使用特殊符号混淆文件名(如shell.txt?.php#.jpg),使系统误判为图片文件但未严格校验文件真实类型及内容,导致攻击者可构造特殊压缩包绕过删除逻辑,保留恶意文件//1.接收用户上传的ZIP压缩包并直接写入临时文件 file_p
使用PHP对接StockTV全球金融市场数据API实战指南
php股票接口
关键词:PHPAPI开发、金融市场数据、WebSocket实时数据、cURL实战一、项目概述StockTV作为全球领先的金融数据平台,提供覆盖股票、外汇、期货和加密货币的实时行情服务。本文将手把手教你使用PHP实现以下核心功能:✅RESTAPI调用:获取历史行情数据✅WebSocket订阅:实时价格推送✅生产级特性:异常重试、速率控制、数据缓存✅高性能优化:连接池、异步处理二、环境准备1.运行环境
效率翻倍!超好用的AI+写作API接口汇总
程序员后端
在过去几年里,人工智能(AI)技术经过众多科技公司和科研人员的不懈努力取得了巨大进步,吸引了大众的广泛关注。这些AI技术在应用领域的新闻报道也逐渐走入人们的视野,引发了对其具体应用的浓厚兴趣。今天,我们将聊一聊AI与写作文案的结合。在传统观念中,AI技术通常被限制在有明确定义任务的领域。然而,实际上,AI在创造性任务,如写作方面,也展现出了强大的潜力。人工智能写作软件提供了多种选择,可用于生成长篇
LangChain教程 - Agent -之 ZERO_SHOT_REACT_DESCRIPTION
花千树-010
LangChain langchain javascript prompt AIGC 自然语言处理 人工智能 python
在构建智能AI助手时,我们希望模型能够智能地调用工具,以便提供准确的信息。LangChain提供了AgentType.ZERO_SHOT_REACT_DESCRIPTION,它结合了ReAct(Reasoning+Acting)策略,使得LLM可以基于工具的描述智能选择合适的工具进行推理和执行。本文将介绍该类型Agent的核心原理,并通过示例展示其应用。1.ZERO_SHOT_REACT_DESC
K8S日常问题优化
沉默的八哥
运维 运维 kubernetes
在实际工作中,优化Kubernetes的性能和成本通常需要结合资源利用率分析、集群配置调整以及自动化工具的整合。以下是我在项目中实践过的一些典型优化场景和解决方案:一、资源利用率优化1.合理配置Requests/Limits问题:许多团队未准确设置Pod的requests和limits,导致资源浪费或频繁OOM。优化方法:使用Prometheus+Grafana监控Pod的实际CPU/内存使用量。
# 量子力学中叠加态、本征态、混合态、纯态、纠缠态、直积态的区别(百度整理来的)
猪猪侠|ZZXia
其他
量子力学中叠加态、本征态、混合态、纯态、纠缠态、直积态的区别(百度整理来的)文章目录量子力学中叠加态、本征态、混合态、纯态、纠缠态、直积态的区别(百度整理来的)1【叠加态、本征态】:2【混合态、纯态】:3【纠缠态、直积态】:4【其他】量子究竟是个什么鬼?难道是比原子、电子更小的粒子吗?其实不是。量子跟原子、电子根本不能比较大小,因为它的本意是一个数学概念,就是“离散变化的最小单元”。离散变化是微观
五大理由告诉你,软考为什么要趁早考!
公众号-希赛网
学习方法 职场和发展
2025年上半年软考已经开始报名了,江苏、贵州、山西、大连、安徽、福建、澳门、兵团、四川、浙江等考区的报名入口已经开通。对于还在犹豫要不要报考的小伙伴们,小希建议趁早考软考。一、软考难度逐渐上升,越晚考越难拿证现在,软考的试题越来越注重考查考生的实践能力,且考得越来越细致。与前几年相比,软考的通过率有了很明显的下降。比如,2020年湖南考区软考的通过率约为23%,2021年上半年约为26%,到20
湖南大学DeepSeek研究:我们该如何看待DeepSeek(附 PDF 下载)
伟贤AI之路
AI技术 人工智能
很多大学最近对DeepSeek相关研究比较多,大家可以通过阅读大学研究文档,学习AI知识及判断未来AI方面发展趋势。下面是其它大学的PDF下载厦门大学DeepSeek手册:从社会大众到高校及企业的全面应用实践研究(附PDF下载)清华北大推出的DeepSeek教程(附PDF下载链接)一、Whatisit:DeepSeek是什么从ChatGPT到DeepSeek-R1,TA到底厉害在哪里?DeepSe
Selenium的键盘操作,组合键(4)
一直开心
python 开发语言
#键盘操作,组合键fromtimeimportsleepfromseleniumimportwebdriverfromselenium.webdriver.common.keysimportKeysfromselenium.webdriver.common.byimportBydriver=webdriver.Chrome()driver.get('https://www.baidu.com/')
mysql主从数据同步
林鹤霄
mysql主从数据同步
配置mysql5.5主从服务器(转)
教程开始:一、安装MySQL
说明:在两台MySQL服务器192.168.21.169和192.168.21.168上分别进行如下操作,安装MySQL 5.5.22
二、配置MySQL主服务器(192.168.21.169)mysql -uroot -p &nb
oracle学习笔记
caoyong
oracle
1、ORACLE的安装
a>、ORACLE的版本
8i,9i : i是internet
10g,11g : grid (网格)
12c : cloud (云计算)
b>、10g不支持win7
&
数据库,SQL零基础入门
天子之骄
sql 数据库入门 基本术语
数据库,SQL零基础入门
做网站肯定离不开数据库,本人之前没怎么具体接触SQL,这几天起早贪黑得各种入门,恶补脑洞。一些具体的知识点,可以让小白不再迷茫的术语,拿来与大家分享。
数据库,永久数据的一个或多个大型结构化集合,通常与更新和查询数据的软件相关
pom.xml
一炮送你回车库
pom.xml
1、一级元素dependencies是可以被子项目继承的
2、一级元素dependencyManagement是定义该项目群里jar包版本号的,通常和一级元素properties一起使用,既然有继承,也肯定有一级元素modules来定义子元素
3、父项目里的一级元素<modules>
<module>lcas-admin-war</module>
<
sql查地区省市县
3213213333332132
sql mysql
-- db_yhm_city
SELECT * FROM db_yhm_city WHERE class_parent_id = 1 -- 海南 class_id = 9 港、奥、台 class_id = 33、34、35
SELECT * FROM db_yhm_city WHERE class_parent_id =169
SELECT d1.cla
关于监听器那些让人头疼的事
宝剑锋梅花香
画图板 监听器 鼠标监听器
本人初学JAVA,对于界面开发我只能说有点蛋疼,用JAVA来做界面的话确实需要一定的耐心(不使用插件,就算使用插件的话也没好多少)既然Java提供了界面开发,老师又要求做,只能硬着头皮上啦。但是监听器还真是个难懂的地方,我是上了几次课才略微搞懂了些。
JAVA的遍历MAP
darkranger
map
Java Map遍历方式的选择
1. 阐述
对于Java中Map的遍历方式,很多文章都推荐使用entrySet,认为其比keySet的效率高很多。理由是:entrySet方法一次拿到所有key和value的集合;而keySet拿到的只是key的集合,针对每个key,都要去Map中额外查找一次value,从而降低了总体效率。那么实际情况如何呢?
为了解遍历性能的真实差距,包括在遍历ke
POJ 2312 Battle City 优先多列+bfs
aijuans
搜索
来源:http://poj.org/problem?id=2312
题意:题目背景就是小时候玩的坦克大战,求从起点到终点最少需要多少步。已知S和R是不能走得,E是空的,可以走,B是砖,只有打掉后才可以通过。
思路:很容易看出来这是一道广搜的题目,但是因为走E和走B所需要的时间不一样,因此不能用普通的队列存点。因为对于走B来说,要先打掉砖才能通过,所以我们可以理解为走B需要两步,而走E是指需要1
Hibernate与Jpa的关系,终于弄懂
avords
java Hibernate 数据库 jpa
我知道Jpa是一种规范,而Hibernate是它的一种实现。除了Hibernate,还有EclipseLink(曾经的toplink),OpenJPA等可供选择,所以使用Jpa的一个好处是,可以更换实现而不必改动太多代码。
在play中定义Model时,使用的是jpa的annotations,比如javax.persistence.Entity, Table, Column, OneToMany
酸爽的console.log
bee1314
console
在前端的开发中,console.log那是开发必备啊,简直直观。通过写小函数,组合大功能。更容易测试。但是在打版本时,就要删除console.log,打完版本进入开发状态又要添加,真不够爽。重复劳动太多。所以可以做些简单地封装,方便开发和上线。
/**
* log.js hufeng
* The safe wrapper for `console.xxx` functions
*
哈佛教授:穷人和过于忙碌的人有一个共同思维特质
bijian1013
时间管理 励志人生 穷人 过于忙碌
一个跨学科团队今年完成了一项对资源稀缺状况下人的思维方式的研究,结论是:穷人和过于忙碌的人有一个共同思维特质,即注意力被稀缺资源过分占据,引起认知和判断力的全面下降。这项研究是心理学、行为经济学和政策研究学者协作的典范。
这个研究源于穆来纳森对自己拖延症的憎恨。他7岁从印度移民美国,很快就如鱼得水,哈佛毕业
other operate
征客丶
OS osx
一、Mac Finder 设置排序方式,预览栏 在显示-》查看显示选项中
二、有时预览显示时,卡死在那,有可能是一些临时文件夹被删除了,如:/private/tmp[有待验证]
--------------------------------------------------------------------
若有其他凝问或文中有错误,请及时向我指出,
我好及时改正,同时也让我们一
【Scala五】分析Spark源代码总结的Scala语法三
bit1129
scala
1. If语句作为表达式
val properties = if (jobIdToActiveJob.contains(jobId)) {
jobIdToActiveJob(stage.jobId).properties
} else {
// this stage will be assigned to "default" po
ZooKeeper 入门
BlueSkator
中间件 zk
ZooKeeper是一个高可用的分布式数据管理与系统协调框架。基于对Paxos算法的实现,使该框架保证了分布式环境中数据的强一致性,也正是基于这样的特性,使得ZooKeeper解决很多分布式问题。网上对ZK的应用场景也有不少介绍,本文将结合作者身边的项目例子,系统地对ZK的应用场景进行一个分门归类的介绍。
值得注意的是,ZK并非天生就是为这些应用场景设计的,都是后来众多开发者根据其框架的特性,利
MySQL取得当前时间的函数是什么 格式化日期的函数是什么
BreakingBad
mysql Date
取得当前时间用 now() 就行。
在数据库中格式化时间 用DATE_FORMA T(date, format) .
根据格式串format 格式化日期或日期和时间值date,返回结果串。
可用DATE_FORMAT( ) 来格式化DATE 或DATETIME 值,以便得到所希望的格式。根据format字符串格式化date值:
%S, %s 两位数字形式的秒( 00,01,
读《研磨设计模式》-代码笔记-组合模式
bylijinnan
java 设计模式
声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/
import java.util.ArrayList;
import java.util.List;
abstract class Component {
public abstract void printStruct(Str
4_JAVA+Oracle面试题(有答案)
chenke
oracle
基础测试题
卷面上不能出现任何的涂写文字,所有的答案要求写在答题纸上,考卷不得带走。
选择题
1、 What will happen when you attempt to compile and run the following code? (3)
public class Static {
static {
int x = 5; // 在static内有效
}
st
新一代工作流系统设计目标
comsci
工作 算法 脚本
用户只需要给工作流系统制定若干个需求,流程系统根据需求,并结合事先输入的组织机构和权限结构,调用若干算法,在流程展示版面上面显示出系统自动生成的流程图,然后由用户根据实际情况对该流程图进行微调,直到满意为止,流程在运行过程中,系统和用户可以根据情况对流程进行实时的调整,包括拓扑结构的调整,权限的调整,内置脚本的调整。。。。。
在这个设计中,最难的地方是系统根据什么来生成流
oracle 行链接与行迁移
daizj
oracle 行迁移
表里的一行对于一个数据块太大的情况有二种(一行在一个数据块里放不下)
第一种情况:
INSERT的时候,INSERT时候行的大小就超一个块的大小。Oracle把这行的数据存储在一连串的数据块里(Oracle Stores the data for the row in a chain of data blocks),这种情况称为行链接(Row Chain),一般不可避免(除非使用更大的数据
[JShop]开源电子商务系统jshop的系统缓存实现
dinguangx
jshop 电子商务
前言
jeeshop中通过SystemManager管理了大量的缓存数据,来提升系统的性能,但这些缓存数据全部都是存放于内存中的,无法满足特定场景的数据更新(如集群环境)。JShop对jeeshop的缓存机制进行了扩展,提供CacheProvider来辅助SystemManager管理这些缓存数据,通过CacheProvider,可以把缓存存放在内存,ehcache,redis,memcache
初三全学年难记忆单词
dcj3sjt126com
english word
several 儿子;若干
shelf 架子
knowledge 知识;学问
librarian 图书管理员
abroad 到国外,在国外
surf 冲浪
wave 浪;波浪
twice 两次;两倍
describe 描写;叙述
especially 特别;尤其
attract 吸引
prize 奖品;奖赏
competition 比赛;竞争
event 大事;事件
O
sphinx实践
dcj3sjt126com
sphinx
安装参考地址:http://briansnelson.com/How_to_install_Sphinx_on_Centos_Server
yum install sphinx
如果失败的话使用下面的方式安装
wget http://sphinxsearch.com/files/sphinx-2.2.9-1.rhel6.x86_64.rpm
yum loca
JPA之JPQL(三)
frank1234
orm jpa JPQL
1 什么是JPQL
JPQL是Java Persistence Query Language的简称,可以看成是JPA中的HQL, JPQL支持各种复杂查询。
2 检索单个对象
@Test
public void querySingleObject1() {
Query query = em.createQuery("sele
Remove Duplicates from Sorted Array II
hcx2013
remove
Follow up for "Remove Duplicates":What if duplicates are allowed at most twice?
For example,Given sorted array nums = [1,1,1,2,2,3],
Your function should return length
Spring4新特性——Groovy Bean定义DSL
jinnianshilongnian
spring 4
Spring4新特性——泛型限定式依赖注入
Spring4新特性——核心容器的其他改进
Spring4新特性——Web开发的增强
Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC
Spring4新特性——Groovy Bean定义DSL
Spring4新特性——更好的Java泛型操作API
Spring4新
CentOS安装Mysql5.5
liuxingguome
centos
CentOS下以RPM方式安装MySQL5.5
首先卸载系统自带Mysql:
yum remove mysql mysql-server mysql-libs compat-mysql51
rm -rf /var/lib/mysql
rm /etc/my.cnf
查看是否还有mysql软件:
rpm -qa|grep mysql
去http://dev.mysql.c
第14章 工具函数(下)
onestopweb
函数
index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/
POJ 1050
SaraWon
二维数组 子矩阵 最大和
POJ ACM第1050题的详细描述,请参照
http://acm.pku.edu.cn/JudgeOnline/problem?id=1050
题目意思:
给定包含有正负整型的二维数组,找出所有子矩阵的和的最大值。
如二维数组
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
中和最大的子矩阵是
9 2
-4 1
-1 8
且最大和是15
[5]设计模式——单例模式
tsface
java 单例 设计模式 虚拟机
单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点
安全的单例模式:
/*
* @(#)Singleton.java 2014-8-1
*
* Copyright 2014 XXXX, Inc. All rights reserved.
*/
package com.fiberhome.singleton;
Java8全新打造,英语学习supertool
yangshangchuan
java superword 闭包 java8 函数式编程
superword是一个Java实现的英文单词分析软件,主要研究英语单词音近形似转化规律、前缀后缀规律、词之间的相似性规律等等。Clean code、Fluent style、Java8 feature: Lambdas, Streams and Functional-style Programming。
升学考试、工作求职、充电提高,都少不了英语的身影,英语对我们来说实在太重要