tomcat(9)Session管理
public interface Session { public static final String SESSION_CREATED_EVENT = "createSession"; public static final String SESSION_DESTROYED_EVENT = "destroySession"; public String getAuthType(); public void setAuthType(String authType); public long getCreationTime(); public void setCreationTime(long time); public String getId(); public void setId(String id); public String getInfo(); public long getLastAccessedTime(); public Manager getManager(); public void setManager(Manager manager); public int getMaxInactiveInterval(); public void setMaxInactiveInterval(int interval); public void setNew(boolean isNew); public Principal getPrincipal(); public void setPrincipal(Principal principal); public HttpSession getSession(); public void setValid(boolean isValid); public boolean isValid(); public void access(); public void addSessionListener(SessionListener listener); public void expire(); public Object getNote(String name); public Iterator getNoteNames(); public void recycle();public void removeNote(String name);public void removeSessionListener(SessionListener listener);public void setNote(String name, Object value);
}
<span style="font-size:18px;">public StandardSession(Manager manager);</span>
class StandardSessionimplements HttpSession, Session, Serializable { public StandardSession(Manager manager) { super();this.manager = manager;if (manager instanceof ManagerBase)this.debug = ((ManagerBase) manager).getDebug();}private static final String NOT_SERIALIZED ="___NOT_SERIALIZABLE_EXCEPTION___"; private HashMap attributes = new HashMap();private transient String authType = null; private transient Method containerEventMethod = null; private static final Class containerEventTypes[] = { String.class, Object.class }; private long creationTime = 0L; private transient int debug = 0;private transient boolean expiring = false;private transient StandardSessionFacade facade = null;private String id = null;private static final String info = "StandardSession/1.0";private long lastAccessedTime = creationTime;private transient ArrayList listeners = new ArrayList(); private Manager manager = null;private int maxInactiveInterval = -1;private boolean isNew = false;private boolean isValid = false;private transient HashMap notes = new HashMap();private transient Principal principal = null;private static StringManager sm =StringManager.getManager(Constants.Package); private static HttpSessionContext sessionContext = null;private transient PropertyChangeSupport support =new PropertyChangeSupport(this); private long lastUsedTime = creationTime;
}
public HttpSession getSession() {if(facade==null){facade = new StandardSessionFacade(this);}return facade;
}
5)设置Session为过期:若Session管理器中的某个Session对象 在某个时间长度内都没有被访问 的话,会被 Session 管理器设置为过期,这个时间长度由变量 maxInactiveInterval 的值来指定;(干货——将一个Session对象设置为过期主要是通过Session接口的expire() 方法来完成的);
public void expire(boolean notify) {// Mark this session as "being expired" if neededif (expiring)return;expiring = true;setValid(false);// Remove this session from our manager's active sessionsif (manager != null)manager.remove(this);// Unbind any objects associated with this sessionString keys[] = keys();for (int i = 0; i < keys.length; i++)removeAttribute(keys[i], notify);// Notify interested session event listenersif (notify) {fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null);}// Notify interested application event listeners// FIXME - Assumes we call listeners in reverse orderContext context = (Context) manager.getContainer();Object listeners[] = context.getApplicationListeners();if (notify && (listeners != null)) {HttpSessionEvent event =new HttpSessionEvent(getSession());for (int i = 0; i < listeners.length; i++) {int j = (listeners.length - 1) - i;if (!(listeners[j] instanceof HttpSessionListener))continue;HttpSessionListener listener =(HttpSessionListener) listeners[j]; try {fireContainerEvent(context, // highlight line."beforeSessionDestroyed",listener);listener.sessionDestroyed(event); // destroy session.fireContainerEvent(context, // also highlight line."afterSessionDestroyed",listener);} catch (Throwable t) {try {fireContainerEvent(context,"afterSessionDestroyed",listener);} catch (Exception e) {;}// FIXME - should we do anything besides log these?log(sm.getString("standardSession.sessionEvent"), t);}}}// We have completed expire of this sessionexpiring = false;if ((manager != null) && (manager instanceof ManagerBase)) {recycle();} }
private void fireContainerEvent(Context context,String type, Object data)throws Exception {if (!"org.apache.catalina.core.StandardContext".equals(context.getClass().getName())) {return; // Container events are not supported}// NOTE: Race condition is harmless, so do not synchronizeif (containerEventMethod == null) {containerEventMethod =context.getClass().getMethod("fireContainerEvent", // terrific line.containerEventTypes);}Object containerEventParams[] = new Object[2];containerEventParams[0] = type;containerEventParams[1] = data;containerEventMethod.invoke(context, containerEventParams);}
public interface Manager { public Container getContainer(); public void setContainer(Container container); public DefaultContext getDefaultContext(); public void setDefaultContext(DefaultContext defaultContext); public boolean getDistributable(); public void setDistributable(boolean distributable); public String getInfo(); public int getMaxInactiveInterval(); public void setMaxInactiveInterval(int interval); public void add(Session session); public Session createEmptySession(); public void addPropertyChangeListener(PropertyChangeListener listener); public Session createSession(); public Session findSession(String id) throws IOException; public Session[] findSessions(); public void load() throws ClassNotFoundException, IOException; public void remove(Session session); public void removePropertyChangeListener(PropertyChangeListener listener); public void unload() throws IOException;
}
A1)getContainer()方法和setContainer()方法:以便将一个Manager实现与一个 Context容器相关联;A2)createSession()方法:用来创建一个Session实例;A3)add()方法:会将一个 Session实例添加到 Session池中;A4)remove()方法:则会将一个 Session实例从 Session池中移除;A5)getMaxInactiveInterval()方法和 setMaxInactiveInterval()方法:用来获取或设置一个时间长度,单位为秒;A6)Session管理器: 会以此作为一个Session对象的最长存活时间;A7)load()方法和unload() 方法:用来将Session对象持久化到辅助存储器中(干货——load方法和unload方法)
A7.1)load方法:该方法会将介质中的Session对象重新载入到内存中;A7.2)unload方法:该方法会将当前活动的 Session对象存储到 Manager 实现指定的介质中;
protected HashMap sessions = new HashMap();
public void add(Session session) {synchronized (sessions) {sessions.put(session.getId(), session);if( sessions.size() > maxActive ) {maxActive=sessions.size();}}}
public void remove(Session session) {synchronized (sessions) {sessions.remove(session.getId());}}
public Session[] findSessions() {Session results[] = null;synchronized (sessions) {results = new Session[sessions.size()];results = (Session[]) sessions.values().toArray(results);}return (results);}
public Session findSession(String id) throws IOException {if (id == null)return (null);synchronized (sessions) {Session session = (Session) sessions.get(id);return (session);}}
public void run() { //org.apache.catalina.session.StandardManager// Loop until the termination semaphore is setwhile (!threadDone) {threadSleep();processExpires();}}
A1)threadSleep()方法:会使线程休眠一段时间,长度由checkInterval指定,default==60 秒;A2)processExpir()方法:会遍历由 Session管理器管理的所有Session对象,将Session实例的lastAccessedTime属性值与当前时间进行比较,如果两者之间的差值超过了变量 maxInactiveInterval 指定的数值,则会调用 Session接口的 expire() 方法使这个Session实例过期;private void processExpires() { // org.apache.catalina.session.StandardManager.processExpires()long timeNow = System.currentTimeMillis();Session sessions[] = findSessions();for (int i = 0; i < sessions.length; i++) {StandardSession session = (StandardSession) sessions[i];if (!session.isValid())continue;int maxInactiveInterval = session.getMaxInactiveInterval();if (maxInactiveInterval < 0)continue;int timeIdle = // Truncate, do not round up(int) ((timeNow - session.getLastUsedTime()) / 1000L);if (timeIdle >= maxInactiveInterval) {try {expiredSessions++;session.expire();// highlight line.} catch (Throwable t) {log(sm.getString("standardManager.expireException"), t);}}}}
A1)在tomcat5中,StandardManager类已不再实现 java.lang.Runnable接口。其中的 backgroundporocess() 方法会直接调用 tomcat5 中StandardManager对象的 processExpires()方法;
public voiid backgroundProcess() { //org.apache.catalina.session.StandardManager.backgroundProcess()processExpire(); }
public void expire() { //org.apache.catalina.sessoin.StandardManager.expire()expire(true);} public void expire(boolean notify) { // the same as the above.// Mark this session as "being expired" if neededif (expiring)return;expiring = true;setValid(false);// Remove this session from our manager's active sessionsif (manager != null)manager.remove(this);// Unbind any objects associated with this sessionString keys[] = keys();for (int i = 0; i < keys.length; i++)removeAttribute(keys[i], notify);// Notify interested session event listenersif (notify) {fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null);}// Notify interested application event listeners// FIXME - Assumes we call listeners in reverse orderContext context = (Context) manager.getContainer();Object listeners[] = context.getApplicationListeners();if (notify && (listeners != null)) {HttpSessionEvent event =new HttpSessionEvent(getSession());for (int i = 0; i < listeners.length; i++) {int j = (listeners.length - 1) - i;if (!(listeners[j] instanceof HttpSessionListener))continue;HttpSessionListener listener =(HttpSessionListener) listeners[j];try {fireContainerEvent(context,"beforeSessionDestroyed",listener);listener.sessionDestroyed(event);fireContainerEvent(context,"afterSessionDestroyed",listener);} catch (Throwable t) {try {fireContainerEvent(context,"afterSessionDestroyed",listener);} catch (Exception e) {;}// FIXME - should we do anything besides log these?log(sm.getString("standardSession.sessionEvent"), t);}}}// We have completed expire of this sessionexpiring = false;if ((manager != null) && (manager instanceof ManagerBase)) {recycle();}}
public void run() { //org.apache.catalina.session.PersistentManagerBase.run()while(!threadDone) {threadSleep();processExpires(); // 检查Session对象是否过期.processPersistenceChecks();}
}
public void processPersistenceChecks(){ // org.apache.catalina.session.PersistentManagerBase.processPersistenceChecks()processMaxIdleSwaps(); // highlight line.(下面我们只以processMaxIdleSwaps方法为例进行调用过程的分析,其他两个方法类似)processMaxActiveSwaps(); // highlight line.processMaxIdleBackups(); // highlight line.
}
/*** Swap idle sessions out to Store if they are idle too long.若session空闲太久则换出*/protected void processMaxIdleSwaps() {if (!isStarted() || maxIdleSwap < 0)return;Session sessions[] = findSessions();long timeNow = System.currentTimeMillis();// Swap out all sessions idle longer than maxIdleSwap// FIXME: What's preventing us from mangling a session during// a request?if (maxIdleSwap >= 0) {for (int i = 0; i < sessions.length; i++) {StandardSession session = (StandardSession) sessions[i];if (!session.isValid())continue;long lastAccessed = ((StandardSession)session).getLastUsedTime();int timeIdle = // Truncate, do not round up(int) ((timeNow - lastAccessed) / 1000L);if (timeIdle > maxIdleSwap && timeIdle > minIdleSwap) {if (debug > 1)log(sm.getString("persistentManager.swapMaxIdle",session.getId(), new Integer(timeIdle)));try {swapOut(session); // highlight line.} catch (IOException e) {; // This is logged in writeSession()}}}}}
protected void swapOut(Session session) throws IOException { //换出操作if (store == null ||!session.isValid() ||isSessionStale(session, System.currentTimeMillis()))return;((StandardSession)session).passivate();writeSession(session); // highlight line.super.remove(session);session.recycle();}
protected void writeSession(Session session) throws IOException {if (store == null ||!session.isValid() ||isSessionStale(session, System.currentTimeMillis()))return;try {store.save(session); //highlight line.sessionSwapIgnore.remove(session.getId());} catch (IOException e) {log(sm.getString("persistentManager.serializeError", session.getId(), e));throw e;}}
4.1.1)当活动的Session实例数量过多时:PersistentManagerBase会将Session对象换出直到数量等于 maxActiveSessions;(参见 processMaxActiveSwaps()方法)4.1.2)当某个Session对象闲置了过长时间:PersistentManagerBase会依据两个变量来决定是否将这个Session换出,这两个变量是minIdleSwap and maxIdleSwap;如果某个Session对象的 lastAccessedTime 属性的值超过了 minIdleSwap 和 maxIdleSwap 的值,就会将这个Session换出;(干货——为了防止换出Session对象,将maxIdleSwap设置为负数,参见 processMaxIdleSwaps() 方法);
public Session findSession(String id) throws IOException { //org.apache.catalina.session.PersistentManagerBase.findSession()Session session = super.findSession(id);if (session != null)return (session);// See if the Session is in the Storesession = swapIn(id); // highlight line.return (session);}
protected Session swapIn(String id) throws IOException { // the same as the above.if (store == null)return null;if (sessionSwapIgnore.contains(id)) {return null;}Session session = null;try {session = store.load(id); // highlight line.} catch (ClassNotFoundException e) {log(sm.getString("persistentManager.deserializeError", id, e));throw new IllegalStateException(sm.getString("persistentManager.deserializeError", id, e));}if (session == null) {sessionSwapIgnore.put(id,id);return (null);}if (!session.isValid()|| isSessionStale(session, System.currentTimeMillis())) {log("session swapped in is invalid or expired");session.expire(); // highlight line.store.remove(id); // highlight line.sessionSwapIgnore.put(id,id);return (null);}if(debug > 2)log(sm.getString("persistentManager.swapIn", id));session.setManager(this);// To make sure the listener knows about it.((StandardSession)session).tellNew();add(session);((StandardSession)session).activate();return (session);}
public final class PersistentManager extends PersistentManagerBase { //org.apache.catalina.session.PersistentManager private static final String info = "PersistentManager/1.0"; protected static String name = "PersistentManager"; public String getInfo() {return (this.info);} public String getName() {return (name);}}
public Session createSession() {Session session = super.createSession(); // step1.ObjectOutputStream oos = null;ByteArrayOutputStream bos = null;ByteArrayInputStream bis = null;try {bos = new ByteArrayOutputStream();oos = new ObjectOutputStream(new BufferedOutputStream(bos));((StandardSession)session).writeObjectData(oos);oos.close();byte[] obs = bos.toByteArray();clusterSender.send(obs); // step2.if(debug > 0)log("Replicating Session: "+session.getId());} catch (IOException e) {log("An error occurred when replicating Session: "+session.getId());}return (session);}
step1)调用超类的 createSession()方法为自身创建一个 Session对象;step2)使用ClusterSender实例,以字节数组的形式将该Session对象发送到集群中的其他节点;
public void run() { // org.apache.catalina.session.DistributedManager.run()// Loop until the termination semaphore is setwhile (!threadDone) {threadSleep();processClusterReceiver(); // 以该方法为例进行说明.processExpires();processPersistenceChecks();}}
/*** Called from our background thread to process new received Sessions**/public void processClusterReceiver() { //org.apache.catalina.session.DistributedManager.processClusterReceiver()Object[] objs = clusterReceiver.getObjects();StandardSession _session = null;ByteArrayInputStream bis = null;Loader loader = null;ClassLoader classLoader = null;ObjectInputStream ois = null;byte[] buf = new byte[5000];ReplicationWrapper repObj = null;for(int i=0; i < objs.length;i++) {try {bis = new ByteArrayInputStream(buf);repObj = (ReplicationWrapper)objs[i];buf = repObj.getDataStream();bis = new ByteArrayInputStream(buf, 0, buf.length);if (container != null)loader = container.getLoader();if (loader != null)classLoader = loader.getClassLoader();if (classLoader != null)ois = new CustomObjectInputStream(bis,classLoader);elseois = new ObjectInputStream(bis);_session = (StandardSession) super.createSession();_session.readObjectData(ois);_session.setManager(this);if (debug > 0)log("Loading replicated session: "+_session.getId());} catch (IOException e) {log("Error occurred when trying to read replicated session: "+e.toString());} catch (ClassNotFoundException e) {log("Error occurred when trying to read replicated session: "+e.toString());} finally {if (ois != null) {try {ois.close();bis = null;} catch (IOException e) {;}}}}}
public interface Store { // org.apache.catalina.Storepublic String getInfo(); public Manager getManager(); public void setManager(Manager manager); public int getSize() throws IOException; public void addPropertyChangeListener(PropertyChangeListener listener); public String[] keys() throws IOException; public Session load(String id) throws ClassNotFoundException, IOException;public void remove(String id) throws IOException; public void clear() throws IOException; public void removePropertyChangeListener(PropertyChangeListener listener); public void save(Session session) throws IOException;
}
public void run() { // org.apache.catalina.session.StoreBase.run()// Loop until the termination semaphore is setwhile (!threadDone) {threadSleep();processExpires();}}
A1)processExpires方法:会获取所有活动的 Session对象,检查 每个Session对象的 lastAccessedTime属性值,删除那些长时间不活动的Session对象;源代码如下:(干货——再次提及了processExpires方法,注意其功能)
protected void processExpires() {// org.apache.catalina.session.StoreBase.processExpires()long timeNow = System.currentTimeMillis();String[] keys = null;if(!started) {return;}try {keys = keys();} catch (IOException e) {log (e.toString());e.printStackTrace();return;}for (int i = 0; i < keys.length; i++) {try {StandardSession session = (StandardSession) load(keys[i]);if (session == null) {continue;}if (!session.isValid()) {continue;}int maxInactiveInterval = session.getMaxInactiveInterval();if (maxInactiveInterval < 0) {continue;}int timeIdle = // Truncate, do not round up(int) ((timeNow - session.getLastUsedTime()) / 1000L);if (timeIdle >= maxInactiveInterval) {if ( ( (PersistentManagerBase) manager).isLoaded( keys[i] )) {// recycle old backup sessionsession.recycle();} else {// expire swapped out sessionsession.expire();}remove(session.getId());}} catch (Exception e) {log ("Session: "+keys[i]+"; "+e.toString());try {remove(keys[i]);} catch (IOException e2) {log (e2.toString());e2.printStackTrace();}}}}
public class SessionServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {System.out.println("SessionServlet -- service");response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("<html>");out.println("<head><title>SessionServlet</title></head>");out.println("<body>");String value = request.getParameter("value");HttpSession session = request.getSession(true);out.println("<br>the previous value is " +(String) session.getAttribute("value"));out.println("<br>the current value is " + value);session.setAttribute("value", value);out.println("<br><hr>");out.println("<form>");out.println("New Value: <input name=value>");out.println("<input type=submit>");out.println("</form>");out.println("</body>");out.println("</html>");}
}
public static void main(String[] args) {//invoke: http://localhost:8080/myApp/SessionSystem.setProperty("catalina.base", System.getProperty("user.dir"));Connector connector = new HttpConnector();Wrapper wrapper1 = new SimpleWrapper();wrapper1.setName("Session");wrapper1.setServletClass("SessionServlet");Context context = new StandardContext();// StandardContext's start method adds a default mappercontext.setPath("/myApp");context.setDocBase("myApp");context.addChild(wrapper1);// context.addServletMapping(pattern, name);// note that we must use /myApp/Session, not just /Session// because the /myApp section must be the same as the path, so the cookie will// be sent back.context.addServletMapping("/myApp/Session", "Session");// add ContextConfig. This listener is important because it configures// StandardContext (sets configured to true), otherwise StandardContext// won't startLifecycleListener listener = new SimpleContextConfig();((Lifecycle) context).addLifecycleListener(listener);// here is our loaderLoader loader = new WebappLoader();// associate the loader with the Contextcontext.setLoader(loader);connector.setContainer(context);// add a ManagerManager manager = new StandardManager(); // highlight line.context.setManager(manager); // highlight line.try {connector.initialize();((Lifecycle) connector).start();((Lifecycle) context).start();// make the application wait until we press a key.System.in.read();((Lifecycle) context).stop();}catch (Exception e) {e.printStackTrace();}}
}
public void invoke(Request request, Response response, ValveContext valveContext)throws IOException, ServletException {SimpleWrapper wrapper = (SimpleWrapper) getContainer();ServletRequest sreq = request.getRequest();ServletResponse sres = response.getResponse();Servlet servlet = null;HttpServletRequest hreq = null;if (sreq instanceof HttpServletRequest)hreq = (HttpServletRequest) sreq;HttpServletResponse hres = null;if (sres instanceof HttpServletResponse)hres = (HttpServletResponse) sres;//-- new addition -----------------------------------Context context = (Context) wrapper.getParent(); // highlight line.request.setContext(context); // highlight line.//-------------------------------------// Allocate a servlet instance to process this requesttry {servlet = wrapper.allocate();if (hres!=null && hreq!=null) {servlet.service(hreq, hres);}else {servlet.service(sreq, sres);}}catch (ServletException e) {}}
Manager manager = null;
if(contect != null)manager = context.getManager();
E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src>java -cp .;lib/servlet.jar;lib/catalina_4_1_24.jar;lib/catalina-5.5.4.jar;lib/naming-common.
jar;lib/commons-collections.jar;lib/naming-resources.jar;lib/;lib/catalina.jar;E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\webroot com/tomca
t/chapter9/startup/Bootstrap
HttpConnector Opening server socket on all host IP addresses
HttpConnector[8080] Starting background thread
WebappLoader[/myApp]: Deploying class repositories to work directory E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src\work\_\_\myApp
Starting Wrapper Session
StandardManager[/myApp]: Seeding random number generator class java.security.SecureRandom
StandardManager[/myApp]: Seeding of random number generator has been completed
SessionServlet -- service
SessionServlet -- service
SessionServlet -- service
SessionServlet -- service
tomcat(9)Session管理相关推荐
- Tomcat的Session管理(三)
摘要:PersistentManager与StandardManager的异同. 之前两篇关于session的文章主要讨论了session相关的创建.查询.过期处理.而我们查看源码的时候都是默认实现是 ...
- Tomcat 的session管理
开发中一个未经优化的使用tomcat提供服务的web应用在某日突然内存溢出,而该服务的缓存信息很少,于是google + code insight了一把,加以总结如下. 新用户访问tomcat下的we ...
- Tomcat源码解析七:Tomcat Session管理机制
前面几篇我们分析了Tomcat的启动,关闭,请求处理的流程,tomcat的classloader机制,本篇将接着分析Tomcat的session管理方面的内容. 在开始之前,我们先来看一下总体上的结构 ...
- Tomcat源码分析(九)--Session管理
本系列转载自 http://blog.csdn.net/haitao111313/article/category/1179996 在明白Tomcat的Session机制之前,先要了解Session, ...
- Tomcat7.0源码分析——Session管理分析(上)
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/beliefer/article/details/52450268 前言 对于广大java开发者而言, ...
- tomcat架构分析 (Session管理)【转】
原文地址:https://www.iteye.com/blog/gearever-1546423 Session管理是JavaEE容器比较重要的一部分,在app中也经常会用到.在开发app时,我们只是 ...
- Redis+Tomcat实现集群的Session管理
Redis+Tomcat实现集群的Session管理 本地环境 JDK java version "1.8.0_102" Tomcat apache-tomcat-7.0.90 R ...
- Tomcat 是如何管理Session的?
概述 学了ConcurrentHashMap却不知如何应用?用了Tomcat的Session却不知其是如何实现的,Session是怎么被创建和销毁的?往下看你就知道了. Session结构 不多废话, ...
- tomcat 使用 memcached管理session ,并且实现统一登录
2019独角兽企业重金招聘Python工程师标准>>> 把tomcat的session存放在memcached 的集中式缓存中,所有的tomcat共享memcached中的https ...
最新文章
- java局部变量全局变量,实例变量的理解
- SVD、SVD++和Asymmetric SVD 以及实例
- TOMCAT 高并发配置
- BeautifulSoup 根据文本内容反查标签
- 在记录实体log信息的时候,2个公司的区别
- sdut 2088 数据结构实验之栈与队列十一:refresh的停车场
- 一文搞懂负载均衡中的一致性哈希算法
- 机器学习这四个东西,你知道吗?
- hadoop关键进程
- navicat 或者workbench 无法连接127.0.0.1(61)的解决方法
- LDA (Linear Discriminate Analysis)Fisher Criteria
- CSS 属性篇(七):Display属性
- linux centos7 配置ftp,Linux Centos7配置ftp服务器
- Java设计模式——策略模式
- Flutter自定义iconfont字体图标
- 无法绑定由多个部分组成的标识符 yvi312082007@163.com。
- netbsd apache php mysql,NetBSD配置aria2的web前端YAAW笔记
- DHTML Cascading style sheet 下载 CSS手册
- DL2 - Improving Deep Neural Networks- Hyperparameter tuning, Regularization and Optimization
- 51单片机教程__模块化编程
热门文章
- 几个冷门字符串算法的学习笔记(最小表示法,exKMP,Lyndon Word)
- CF1305F Kuroni and the Punishment
- Codeforces Round #691 (Div. 1)
- Drainage Ditches POJ1273
- P7516-[省选联考2021A/B卷]图函数【bfs】
- UOJ#33-[UR #2]树上GCD【长链剖分,根号分治】
- P2052-[NOI2011]道路修建【树】
- 欢乐纪中某A组赛【2019.7.9】
- nssl1231-Gift【01背包,dp】
- ssl1614-医院设置【图论,最短路】