<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.5">Jekyll</generator><link href="https://www.kuradeon.cn/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.kuradeon.cn/" rel="alternate" type="text/html" /><updated>2024-02-16T10:19:09+00:00</updated><id>https://www.kuradeon.cn/feed.xml</id><title type="html">Kuradeon’s Blog</title><subtitle>This is a blog.
</subtitle><author><name>Kuradeon</name></author><entry><title type="html">Spring 拓展点总结</title><link href="https://www.kuradeon.cn/2019/05/13/Spring%E6%8B%93%E5%B1%95%E7%82%B9.html" rel="alternate" type="text/html" title="Spring 拓展点总结" /><published>2019-05-13T00:00:00+00:00</published><updated>2019-05-13T00:00:00+00:00</updated><id>https://www.kuradeon.cn/2019/05/13/Spring%E6%8B%93%E5%B1%95%E7%82%B9</id><content type="html" xml:base="https://www.kuradeon.cn/2019/05/13/Spring%E6%8B%93%E5%B1%95%E7%82%B9.html"><![CDATA[<h1 id="spring-拓展点">Spring 拓展点</h1>

<h2 id="定位">定位</h2>

<h3 id="applicationcontextinitializer">ApplicationContextInitializer</h3>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * Callback interface for initializing a Spring {@link ConfigurableApplicationContext}
 * prior to being {@linkplain ConfigurableApplicationContext#refresh() refreshed}.
 *
 * &lt;p&gt;Typically used within web applications that require some programmatic initialization
 * of the application context. For example, registering property sources or activating
 * profiles against the {@linkplain ConfigurableApplicationContext#getEnvironment()
 * context's environment}. See {@code ContextLoader} and {@code FrameworkServlet} support
 * for declaring a "contextInitializerClasses" context-param and init-param, respectively.
 *
 * &lt;p&gt;{@code ApplicationContextInitializer} processors are encouraged to detect
 * whether Spring's {@link org.springframework.core.Ordered Ordered} interface has been
 * implemented or if the @{@link org.springframework.core.annotation.Order Order}
 * annotation is present and to sort instances accordingly if so prior to invocation.
 *
 * @author Chris Beams
 * @since 3.1
 * @param &lt;C&gt; the application context type
 * @see org.springframework.web.context.ContextLoader#customizeContext
 * @see org.springframework.web.context.ContextLoader#CONTEXT_INITIALIZER_CLASSES_PARAM
 * @see org.springframework.web.servlet.FrameworkServlet#setContextInitializerClasses
 * @see org.springframework.web.servlet.FrameworkServlet#applyInitializers
 */</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">ApplicationContextInitializer</span><span class="o">&lt;</span><span class="no">C</span> <span class="kd">extends</span> <span class="nc">ConfigurableApplicationContext</span><span class="o">&gt;</span> <span class="o">{</span>

   <span class="cm">/**
    * Initialize the given application context.
    * @param applicationContext the application to configure
    */</span>
   <span class="kt">void</span> <span class="nf">initialize</span><span class="o">(</span><span class="no">C</span> <span class="n">applicationContext</span><span class="o">);</span>

<span class="o">}</span>
</code></pre></div></div>

<p>在<code class="language-plaintext highlighter-rouge">ApplicationContext</code>调用<code class="language-plaintext highlighter-rouge">refresh()</code>之前提供回调，如实现自定义路径的资源加载。</p>

<!--more-->

<h2 id="注册">注册</h2>

<h3 id="beandefinitionregistrypostprocessor">BeanDefinitionRegistryPostProcessor</h3>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for
 * the registration of further bean definitions &lt;i&gt;before&lt;/i&gt; regular
 * BeanFactoryPostProcessor detection kicks in. In particular,
 * BeanDefinitionRegistryPostProcessor may register further bean definitions
 * which in turn define BeanFactoryPostProcessor instances.
 *
 * @author Juergen Hoeller
 * @since 3.0.1
 * @see org.springframework.context.annotation.ConfigurationClassPostProcessor
 */</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">BeanDefinitionRegistryPostProcessor</span> <span class="kd">extends</span> <span class="nc">BeanFactoryPostProcessor</span> <span class="o">{</span>

   <span class="cm">/**
    * Modify the application context's internal bean definition registry after its
    * standard initialization. All regular bean definitions will have been loaded,
    * but no beans will have been instantiated yet. This allows for adding further
    * bean definitions before the next post-processing phase kicks in.
    * @param registry the bean definition registry used by the application context
    * @throws org.springframework.beans.BeansException in case of errors
    */</span>
   <span class="kt">void</span> <span class="nf">postProcessBeanDefinitionRegistry</span><span class="o">(</span><span class="nc">BeanDefinitionRegistry</span> <span class="n">registry</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">BeansException</span><span class="o">;</span>

<span class="o">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">BeanDefinitionRegistryPostProcessor</code>继承了<code class="language-plaintext highlighter-rouge">BeanFactoryPostProcessor</code>，在<code class="language-plaintext highlighter-rouge">BeanDefinition</code>注册时候，<code class="language-plaintext highlighter-rouge">Bean</code>实例化之前回调。可以用来注册更多的<code class="language-plaintext highlighter-rouge">BeanDefinition</code>，也可以用来注册<code class="language-plaintext highlighter-rouge">BeanFactoryPostProcessor</code>的<code class="language-plaintext highlighter-rouge">BeanDefinition</code>。</p>

<pre><code class="language-sequence">postProcessBeanDefinitionRegistry-&gt;postProcessBeanFactory:
</code></pre>

<h3 id="beanfactorypostprocessor">BeanFactoryPostProcessor</h3>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * Allows for custom modification of an application context's bean definitions,
 * adapting the bean property values of the context's underlying bean factory.
 *
 * &lt;p&gt;Application contexts can auto-detect BeanFactoryPostProcessor beans in
 * their bean definitions and apply them before any other beans get created.
 *
 * &lt;p&gt;Useful for custom config files targeted at system administrators that
 * override bean properties configured in the application context.
 *
 * &lt;p&gt;See PropertyResourceConfigurer and its concrete implementations
 * for out-of-the-box solutions that address such configuration needs.
 *
 * &lt;p&gt;A BeanFactoryPostProcessor may interact with and modify bean
 * definitions, but never bean instances. Doing so may cause premature bean
 * instantiation, violating the container and causing unintended side-effects.
 * If bean instance interaction is required, consider implementing
 * {@link BeanPostProcessor} instead.
 *
 * @author Juergen Hoeller
 * @since 06.07.2003
 * @see BeanPostProcessor
 * @see PropertyResourceConfigurer
 */</span>
<span class="nd">@FunctionalInterface</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">BeanFactoryPostProcessor</span> <span class="o">{</span>

	<span class="cm">/**
	 * Modify the application context's internal bean factory after its standard
	 * initialization. All bean definitions will have been loaded, but no beans
	 * will have been instantiated yet. This allows for overriding or adding
	 * properties even to eager-initializing beans.
	 * @param beanFactory the bean factory used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */</span>
	<span class="kt">void</span> <span class="nf">postProcessBeanFactory</span><span class="o">(</span><span class="nc">ConfigurableListableBeanFactory</span> <span class="n">beanFactory</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">BeansException</span><span class="o">;</span>

<span class="o">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">Bean</code>实例化之前，可以通过此拓展点读取<code class="language-plaintext highlighter-rouge">BeanDefinition</code>的配置信息。如其实现类<code class="language-plaintext highlighter-rouge">PropertyPlaceholderConfigurer</code>，可以读取外部<code class="language-plaintext highlighter-rouge">.properties</code>文件来设置<code class="language-plaintext highlighter-rouge">BeanDefinition</code>。</p>

<h2 id="初始化实例化">初始化、实例化</h2>

<h3 id="instantiationawarebeanpostprocessor">InstantiationAwareBeanPostProcessor</h3>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * Subinterface of {@link BeanPostProcessor} that adds a before-instantiation callback,
 * and a callback after instantiation but before explicit properties are set or
 * autowiring occurs.
 *
 * &lt;p&gt;Typically used to suppress default instantiation for specific target beans,
 * for example to create proxies with special TargetSources (pooling targets,
 * lazily initializing targets, etc), or to implement additional injection strategies
 * such as field injection.
 *
 * &lt;p&gt;&lt;b&gt;NOTE:&lt;/b&gt; This interface is a special purpose interface, mainly for
 * internal use within the framework. It is recommended to implement the plain
 * {@link BeanPostProcessor} interface as far as possible, or to derive from
 * {@link InstantiationAwareBeanPostProcessorAdapter} in order to be shielded
 * from extensions to this interface.
 *
 * @author Juergen Hoeller
 * @author Rod Johnson
 * @since 1.2
 * @see org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#setCustomTargetSourceCreators
 * @see org.springframework.aop.framework.autoproxy.target.LazyInitTargetSourceCreator
 */</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">InstantiationAwareBeanPostProcessor</span> <span class="kd">extends</span> <span class="nc">BeanPostProcessor</span> <span class="o">{</span>

   <span class="cm">/**
    * Apply this BeanPostProcessor &lt;i&gt;before the target bean gets instantiated&lt;/i&gt;.
    * The returned bean object may be a proxy to use instead of the target bean,
    * effectively suppressing default instantiation of the target bean.
    * &lt;p&gt;If a non-null object is returned by this method, the bean creation process
    * will be short-circuited. The only further processing applied is the
    * {@link #postProcessAfterInitialization} callback from the configured
    * {@link BeanPostProcessor BeanPostProcessors}.
    * &lt;p&gt;This callback will only be applied to bean definitions with a bean class.
    * In particular, it will not be applied to beans with a factory method.
    * &lt;p&gt;Post-processors may implement the extended
    * {@link SmartInstantiationAwareBeanPostProcessor} interface in order
    * to predict the type of the bean object that they are going to return here.
    * &lt;p&gt;The default implementation returns {@code null}.
    * @param beanClass the class of the bean to be instantiated
    * @param beanName the name of the bean
    * @return the bean object to expose instead of a default instance of the target bean,
    * or {@code null} to proceed with default instantiation
    * @throws org.springframework.beans.BeansException in case of errors
    * @see #postProcessAfterInstantiation
    * @see org.springframework.beans.factory.support.AbstractBeanDefinition#hasBeanClass
    */</span>
   <span class="nd">@Nullable</span>
   <span class="k">default</span> <span class="nc">Object</span> <span class="nf">postProcessBeforeInstantiation</span><span class="o">(</span><span class="nc">Class</span><span class="o">&lt;?&gt;</span> <span class="n">beanClass</span><span class="o">,</span> <span class="nc">String</span> <span class="n">beanName</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">BeansException</span> <span class="o">{</span>
      <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
   <span class="o">}</span>

   <span class="cm">/**
    * Perform operations after the bean has been instantiated, via a constructor or factory method,
    * but before Spring property population (from explicit properties or autowiring) occurs.
    * &lt;p&gt;This is the ideal callback for performing custom field injection on the given bean
    * instance, right before Spring's autowiring kicks in.
    * &lt;p&gt;The default implementation returns {@code true}.
    * @param bean the bean instance created, with properties not having been set yet
    * @param beanName the name of the bean
    * @return {@code true} if properties should be set on the bean; {@code false}
    * if property population should be skipped. Normal implementations should return {@code true}.
    * Returning {@code false} will also prevent any subsequent InstantiationAwareBeanPostProcessor
    * instances being invoked on this bean instance.
    * @throws org.springframework.beans.BeansException in case of errors
    * @see #postProcessBeforeInstantiation
    */</span>
   <span class="k">default</span> <span class="kt">boolean</span> <span class="nf">postProcessAfterInstantiation</span><span class="o">(</span><span class="nc">Object</span> <span class="n">bean</span><span class="o">,</span> <span class="nc">String</span> <span class="n">beanName</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">BeansException</span> <span class="o">{</span>
      <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
   <span class="o">}</span>

   <span class="cm">/**
    * Post-process the given property values before the factory applies them
    * to the given bean, without any need for property descriptors.
    * &lt;p&gt;Implementations should return {@code null} (the default) if they provide a custom
    * {@link #postProcessPropertyValues} implementation, and {@code pvs} otherwise.
    * In a future version of this interface (with {@link #postProcessPropertyValues} removed),
    * the default implementation will return the given {@code pvs} as-is directly.
    * @param pvs the property values that the factory is about to apply (never {@code null})
    * @param bean the bean instance created, but whose properties have not yet been set
    * @param beanName the name of the bean
    * @return the actual property values to apply to the given bean (can be the passed-in
    * PropertyValues instance), or {@code null} which proceeds with the existing properties
    * but specifically continues with a call to {@link #postProcessPropertyValues}
    * (requiring initialized {@code PropertyDescriptor}s for the current bean class)
    * @throws org.springframework.beans.BeansException in case of errors
    * @since 5.1
    * @see #postProcessPropertyValues
    */</span>
   <span class="nd">@Nullable</span>
   <span class="k">default</span> <span class="nc">PropertyValues</span> <span class="nf">postProcessProperties</span><span class="o">(</span><span class="nc">PropertyValues</span> <span class="n">pvs</span><span class="o">,</span> <span class="nc">Object</span> <span class="n">bean</span><span class="o">,</span> <span class="nc">String</span> <span class="n">beanName</span><span class="o">)</span>
         <span class="kd">throws</span> <span class="nc">BeansException</span> <span class="o">{</span>

      <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
   <span class="o">}</span>

   <span class="cm">/**
    * Post-process the given property values before the factory applies them
    * to the given bean. Allows for checking whether all dependencies have been
    * satisfied, for example based on a "Required" annotation on bean property setters.
    * &lt;p&gt;Also allows for replacing the property values to apply, typically through
    * creating a new MutablePropertyValues instance based on the original PropertyValues,
    * adding or removing specific values.
    * &lt;p&gt;The default implementation returns the given {@code pvs} as-is.
    * @param pvs the property values that the factory is about to apply (never {@code null})
    * @param pds the relevant property descriptors for the target bean (with ignored
    * dependency types - which the factory handles specifically - already filtered out)
    * @param bean the bean instance created, but whose properties have not yet been set
    * @param beanName the name of the bean
    * @return the actual property values to apply to the given bean (can be the passed-in
    * PropertyValues instance), or {@code null} to skip property population
    * @throws org.springframework.beans.BeansException in case of errors
    * @see #postProcessProperties
    * @see org.springframework.beans.MutablePropertyValues
    * @deprecated as of 5.1, in favor of {@link #postProcessProperties(PropertyValues, Object, String)}
    */</span>
   <span class="nd">@Deprecated</span>
   <span class="nd">@Nullable</span>
   <span class="k">default</span> <span class="nc">PropertyValues</span> <span class="nf">postProcessPropertyValues</span><span class="o">(</span>
         <span class="nc">PropertyValues</span> <span class="n">pvs</span><span class="o">,</span> <span class="nc">PropertyDescriptor</span><span class="o">[]</span> <span class="n">pds</span><span class="o">,</span> <span class="nc">Object</span> <span class="n">bean</span><span class="o">,</span> <span class="nc">String</span> <span class="n">beanName</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">BeansException</span> <span class="o">{</span>

      <span class="k">return</span> <span class="n">pvs</span><span class="o">;</span>
   <span class="o">}</span>

<span class="o">}</span>
</code></pre></div></div>

<p>继承了<code class="language-plaintext highlighter-rouge">BeanPostProcessor</code>，在此基础上添加了实例化前、实例化后和处理<code class="language-plaintext highlighter-rouge">Bean</code>属性之前的拓展。通常用作创建代理。</p>

<h3 id="beanpostprocessor">BeanPostProcessor</h3>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * Factory hook that allows for custom modification of new bean instances,
 * e.g. checking for marker interfaces or wrapping them with proxies.
 *
 * &lt;p&gt;ApplicationContexts can autodetect BeanPostProcessor beans in their
 * bean definitions and apply them to any beans subsequently created.
 * Plain bean factories allow for programmatic registration of post-processors,
 * applying to all beans created through this factory.
 *
 * &lt;p&gt;Typically, post-processors that populate beans via marker interfaces
 * or the like will implement {@link #postProcessBeforeInitialization},
 * while post-processors that wrap beans with proxies will normally
 * implement {@link #postProcessAfterInitialization}.
 *
 * @author Juergen Hoeller
 * @since 10.10.2003
 * @see InstantiationAwareBeanPostProcessor
 * @see DestructionAwareBeanPostProcessor
 * @see ConfigurableBeanFactory#addBeanPostProcessor
 * @see BeanFactoryPostProcessor
 */</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">BeanPostProcessor</span> <span class="o">{</span>

	<span class="cm">/**
	 * Apply this BeanPostProcessor to the given new bean instance &lt;i&gt;before&lt;/i&gt; any bean
	 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
	 * or a custom init-method). The bean will already be populated with property values.
	 * The returned bean instance may be a wrapper around the original.
	 * &lt;p&gt;The default implementation returns the given {@code bean} as-is.
	 * @param bean the new bean instance
	 * @param beanName the name of the bean
	 * @return the bean instance to use, either the original or a wrapped one;
	 * if {@code null}, no subsequent BeanPostProcessors will be invoked
	 * @throws org.springframework.beans.BeansException in case of errors
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
	 */</span>
	<span class="nd">@Nullable</span>
	<span class="k">default</span> <span class="nc">Object</span> <span class="nf">postProcessBeforeInitialization</span><span class="o">(</span><span class="nc">Object</span> <span class="n">bean</span><span class="o">,</span> <span class="nc">String</span> <span class="n">beanName</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">BeansException</span> <span class="o">{</span>
		<span class="k">return</span> <span class="n">bean</span><span class="o">;</span>
	<span class="o">}</span>

	<span class="cm">/**
	 * Apply this BeanPostProcessor to the given new bean instance &lt;i&gt;after&lt;/i&gt; any bean
	 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
	 * or a custom init-method). The bean will already be populated with property values.
	 * The returned bean instance may be a wrapper around the original.
	 * &lt;p&gt;In case of a FactoryBean, this callback will be invoked for both the FactoryBean
	 * instance and the objects created by the FactoryBean (as of Spring 2.0). The
	 * post-processor can decide whether to apply to either the FactoryBean or created
	 * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
	 * &lt;p&gt;This callback will also be invoked after a short-circuiting triggered by a
	 * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
	 * in contrast to all other BeanPostProcessor callbacks.
	 * &lt;p&gt;The default implementation returns the given {@code bean} as-is.
	 * @param bean the new bean instance
	 * @param beanName the name of the bean
	 * @return the bean instance to use, either the original or a wrapped one;
	 * if {@code null}, no subsequent BeanPostProcessors will be invoked
	 * @throws org.springframework.beans.BeansException in case of errors
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
	 * @see org.springframework.beans.factory.FactoryBean
	 */</span>
	<span class="nd">@Nullable</span>
	<span class="k">default</span> <span class="nc">Object</span> <span class="nf">postProcessAfterInitialization</span><span class="o">(</span><span class="nc">Object</span> <span class="n">bean</span><span class="o">,</span> <span class="nc">String</span> <span class="n">beanName</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">BeansException</span> <span class="o">{</span>
		<span class="k">return</span> <span class="n">bean</span><span class="o">;</span>
	<span class="o">}</span>

<span class="o">}</span>
</code></pre></div></div>

<p>其中<code class="language-plaintext highlighter-rouge">postProcessBeforeInitialization</code>在<code class="language-plaintext highlighter-rouge">bean</code>初始化前提供回调，<code class="language-plaintext highlighter-rouge">postProcessAfterInitialization</code>在<code class="language-plaintext highlighter-rouge">bean</code>初始化后提供回调。</p>

<p>可以通过<code class="language-plaintext highlighter-rouge">postProcessBeforeInitialization</code>自定义返回的<code class="language-plaintext highlighter-rouge">bean</code>实例；可以通过<code class="language-plaintext highlighter-rouge">postProcessAfterInitialization</code>在<code class="language-plaintext highlighter-rouge">bean</code>实例化后修改原有的<code class="language-plaintext highlighter-rouge">bean</code>，如对其包装等。</p>

<h3 id="aware">Aware</h3>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * A marker superinterface indicating that a bean is eligible to be notified by the
 * Spring container of a particular framework object through a callback-style method.
 * The actual method signature is determined by individual subinterfaces but should
 * typically consist of just one void-returning method that accepts a single argument.
 *
 * &lt;p&gt;Note that merely implementing {@link Aware} provides no default functionality.
 * Rather, processing must be done explicitly, for example in a
 * {@link org.springframework.beans.factory.config.BeanPostProcessor}.
 * Refer to {@link org.springframework.context.support.ApplicationContextAwareProcessor}
 * for an example of processing specific {@code *Aware} interface callbacks.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.1
 */</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">Aware</span> <span class="o">{</span>

<span class="o">}</span>
</code></pre></div></div>

<p>各种<code class="language-plaintext highlighter-rouge">Aware</code>的实现类都可提供拓展，下面介绍3种。</p>

<h4 id="beannameaware">BeanNameAware</h4>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * Interface to be implemented by beans that want to be aware of their
 * bean name in a bean factory. Note that it is not usually recommended
 * that an object depends on its bean name, as this represents a potentially
 * brittle dependence on external configuration, as well as a possibly
 * unnecessary dependence on a Spring API.
 *
 * &lt;p&gt;For a list of all bean lifecycle methods, see the
 * {@link BeanFactory BeanFactory javadocs}.
 *
 * @author Juergen Hoeller
 * @author Chris Beams
 * @since 01.11.2003
 * @see BeanClassLoaderAware
 * @see BeanFactoryAware
 * @see InitializingBean
 */</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">BeanNameAware</span> <span class="kd">extends</span> <span class="nc">Aware</span> <span class="o">{</span>

	<span class="cm">/**
	 * Set the name of the bean in the bean factory that created this bean.
	 * &lt;p&gt;Invoked after population of normal bean properties but before an
	 * init callback such as {@link InitializingBean#afterPropertiesSet()}
	 * or a custom init-method.
	 * @param name the name of the bean in the factory.
	 * Note that this name is the actual bean name used in the factory, which may
	 * differ from the originally specified name: in particular for inner bean
	 * names, the actual bean name might have been made unique through appending
	 * "#..." suffixes. Use the {@link BeanFactoryUtils#originalBeanName(String)}
	 * method to extract the original bean name (without suffix), if desired.
	 */</span>
	<span class="kt">void</span> <span class="nf">setBeanName</span><span class="o">(</span><span class="nc">String</span> <span class="n">name</span><span class="o">);</span>

<span class="o">}</span>
</code></pre></div></div>

<p>实现了该接口的<code class="language-plaintext highlighter-rouge">Bean</code>，在实例化之前会回调，获得<code class="language-plaintext highlighter-rouge">BeanName</code>。</p>

<h4 id="applicationcontextaware">ApplicationContextAware</h4>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * Interface to be implemented by any object that wishes to be notified
 * of the {@link ApplicationContext} that it runs in.
 *
 * &lt;p&gt;Implementing this interface makes sense for example when an object
 * requires access to a set of collaborating beans. Note that configuration
 * via bean references is preferable to implementing this interface just
 * for bean lookup purposes.
 *
 * &lt;p&gt;This interface can also be implemented if an object needs access to file
 * resources, i.e. wants to call {@code getResource}, wants to publish
 * an application event, or requires access to the MessageSource. However,
 * it is preferable to implement the more specific {@link ResourceLoaderAware},
 * {@link ApplicationEventPublisherAware} or {@link MessageSourceAware} interface
 * in such a specific scenario.
 *
 * &lt;p&gt;Note that file resource dependencies can also be exposed as bean properties
 * of type {@link org.springframework.core.io.Resource}, populated via Strings
 * with automatic type conversion by the bean factory. This removes the need
 * for implementing any callback interface just for the purpose of accessing
 * a specific file resource.
 *
 * &lt;p&gt;{@link org.springframework.context.support.ApplicationObjectSupport} is a
 * convenience base class for application objects, implementing this interface.
 *
 * &lt;p&gt;For a list of all bean lifecycle methods, see the
 * {@link org.springframework.beans.factory.BeanFactory BeanFactory javadocs}.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Chris Beams
 * @see ResourceLoaderAware
 * @see ApplicationEventPublisherAware
 * @see MessageSourceAware
 * @see org.springframework.context.support.ApplicationObjectSupport
 * @see org.springframework.beans.factory.BeanFactoryAware
 */</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">ApplicationContextAware</span> <span class="kd">extends</span> <span class="nc">Aware</span> <span class="o">{</span>

	<span class="cm">/**
	 * Set the ApplicationContext that this object runs in.
	 * Normally this call will be used to initialize the object.
	 * &lt;p&gt;Invoked after population of normal bean properties but before an init callback such
	 * as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
	 * or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
	 * {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
	 * {@link MessageSourceAware}, if applicable.
	 * @param applicationContext the ApplicationContext object to be used by this object
	 * @throws ApplicationContextException in case of context initialization errors
	 * @throws BeansException if thrown by application context methods
	 * @see org.springframework.beans.factory.BeanInitializationException
	 */</span>
	<span class="kt">void</span> <span class="nf">setApplicationContext</span><span class="o">(</span><span class="nc">ApplicationContext</span> <span class="n">applicationContext</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">BeansException</span><span class="o">;</span>

<span class="o">}</span>
</code></pre></div></div>

<p>实现了该接口的<code class="language-plaintext highlighter-rouge">Bean</code>，在初始化后，会被注入<code class="language-plaintext highlighter-rouge">ApplicationContext</code>。</p>

<h4 id="beanfactoryaware">BeanFactoryAware</h4>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * Interface to be implemented by beans that wish to be aware of their
 * owning {@link BeanFactory}.
 *
 * &lt;p&gt;For example, beans can look up collaborating beans via the factory
 * (Dependency Lookup). Note that most beans will choose to receive references
 * to collaborating beans via corresponding bean properties or constructor
 * arguments (Dependency Injection).
 *
 * &lt;p&gt;For a list of all bean lifecycle methods, see the
 * {@link BeanFactory BeanFactory javadocs}.
 *
 * @author Rod Johnson
 * @author Chris Beams
 * @since 11.03.2003
 * @see BeanNameAware
 * @see BeanClassLoaderAware
 * @see InitializingBean
 * @see org.springframework.context.ApplicationContextAware
 */</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">BeanFactoryAware</span> <span class="kd">extends</span> <span class="nc">Aware</span> <span class="o">{</span>

	<span class="cm">/**
	 * Callback that supplies the owning factory to a bean instance.
	 * &lt;p&gt;Invoked after the population of normal bean properties
	 * but before an initialization callback such as
	 * {@link InitializingBean#afterPropertiesSet()} or a custom init-method.
	 * @param beanFactory owning BeanFactory (never {@code null}).
	 * The bean can immediately call methods on the factory.
	 * @throws BeansException in case of initialization errors
	 * @see BeanInitializationException
	 */</span>
	<span class="kt">void</span> <span class="nf">setBeanFactory</span><span class="o">(</span><span class="nc">BeanFactory</span> <span class="n">beanFactory</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">BeansException</span><span class="o">;</span>

<span class="o">}</span>
</code></pre></div></div>

<p>实现了此接口的<code class="language-plaintext highlighter-rouge">Bean</code>，在处理属性之后，初始化之前，会回调注入<code class="language-plaintext highlighter-rouge">BeanFactory</code>。</p>

<h3 id="initializingbean">InitializingBean</h3>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * Interface to be implemented by beans that need to react once all their properties
 * have been set by a {@link BeanFactory}: e.g. to perform custom initialization,
 * or merely to check that all mandatory properties have been set.
 *
 * &lt;p&gt;An alternative to implementing {@code InitializingBean} is specifying a custom
 * init method, for example in an XML bean definition. For a list of all bean
 * lifecycle methods, see the {@link BeanFactory BeanFactory javadocs}.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @see DisposableBean
 * @see org.springframework.beans.factory.config.BeanDefinition#getPropertyValues()
 * @see org.springframework.beans.factory.support.AbstractBeanDefinition#getInitMethodName()
 */</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">InitializingBean</span> <span class="o">{</span>

   <span class="cm">/**
    * Invoked by the containing {@code BeanFactory} after it has set all bean properties
    * and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
    * &lt;p&gt;This method allows the bean instance to perform validation of its overall
    * configuration and final initialization when all bean properties have been set.
    * @throws Exception in the event of misconfiguration (such as failure to set an
    * essential property) or if initialization fails for any other reason
    */</span>
   <span class="kt">void</span> <span class="nf">afterPropertiesSet</span><span class="o">()</span> <span class="kd">throws</span> <span class="nc">Exception</span><span class="o">;</span>

<span class="o">}</span>
</code></pre></div></div>

<p>在<code class="language-plaintext highlighter-rouge">Bean</code>被注入所有的属性之后回调。</p>

<h3 id="disposablebean">DisposableBean</h3>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * Interface to be implemented by beans that want to release resources on destruction.
 * A {@link BeanFactory} will invoke the destroy method on individual destruction of a
 * scoped bean. An {@link org.springframework.context.ApplicationContext} is supposed
 * to dispose all of its singletons on shutdown, driven by the application lifecycle.
 *
 * &lt;p&gt;A Spring-managed bean may also implement Java's {@link AutoCloseable} interface
 * for the same purpose. An alternative to implementing an interface is specifying a
 * custom destroy method, for example in an XML bean definition. For a list of all
 * bean lifecycle methods, see the {@link BeanFactory BeanFactory javadocs}.
 *
 * @author Juergen Hoeller
 * @since 12.08.2003
 * @see InitializingBean
 * @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName()
 * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons()
 * @see org.springframework.context.ConfigurableApplicationContext#close()
 */</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">DisposableBean</span> <span class="o">{</span>

	<span class="cm">/**
	 * Invoked by the containing {@code BeanFactory} on destruction of a bean.
	 * @throws Exception in case of shutdown errors. Exceptions will get logged
	 * but not rethrown to allow other beans to release their resources as well.
	 */</span>
	<span class="kt">void</span> <span class="nf">destroy</span><span class="o">()</span> <span class="kd">throws</span> <span class="nc">Exception</span><span class="o">;</span>

<span class="o">}</span>
</code></pre></div></div>

<p>在<code class="language-plaintext highlighter-rouge">Bean</code>销毁前提供回调。</p>

<h3 id="factorybean">FactoryBean</h3>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * Interface to be implemented by objects used within a {@link BeanFactory} which
 * are themselves factories for individual objects. If a bean implements this
 * interface, it is used as a factory for an object to expose, not directly as a
 * bean instance that will be exposed itself.
 *
 * &lt;p&gt;&lt;b&gt;NB: A bean that implements this interface cannot be used as a normal bean.&lt;/b&gt;
 * A FactoryBean is defined in a bean style, but the object exposed for bean
 * references ({@link #getObject()}) is always the object that it creates.
 *
 * &lt;p&gt;FactoryBeans can support singletons and prototypes, and can either create
 * objects lazily on demand or eagerly on startup. The {@link SmartFactoryBean}
 * interface allows for exposing more fine-grained behavioral metadata.
 *
 * &lt;p&gt;This interface is heavily used within the framework itself, for example for
 * the AOP {@link org.springframework.aop.framework.ProxyFactoryBean} or the
 * {@link org.springframework.jndi.JndiObjectFactoryBean}. It can be used for
 * custom components as well; however, this is only common for infrastructure code.
 *
 * &lt;p&gt;&lt;b&gt;{@code FactoryBean} is a programmatic contract. Implementations are not
 * supposed to rely on annotation-driven injection or other reflective facilities.&lt;/b&gt;
 * {@link #getObjectType()} {@link #getObject()} invocations may arrive early in
 * the bootstrap process, even ahead of any post-processor setup. If you need access
 * other beans, implement {@link BeanFactoryAware} and obtain them programmatically.
 *
 * &lt;p&gt;Finally, FactoryBean objects participate in the containing BeanFactory's
 * synchronization of bean creation. There is usually no need for internal
 * synchronization other than for purposes of lazy initialization within the
 * FactoryBean itself (or the like).
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 08.03.2003
 * @param &lt;T&gt; the bean type
 * @see org.springframework.beans.factory.BeanFactory
 * @see org.springframework.aop.framework.ProxyFactoryBean
 * @see org.springframework.jndi.JndiObjectFactoryBean
 */</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">FactoryBean</span><span class="o">&lt;</span><span class="no">T</span><span class="o">&gt;</span> <span class="o">{</span>

	<span class="cm">/**
	 * Return an instance (possibly shared or independent) of the object
	 * managed by this factory.
	 * &lt;p&gt;As with a {@link BeanFactory}, this allows support for both the
	 * Singleton and Prototype design pattern.
	 * &lt;p&gt;If this FactoryBean is not fully initialized yet at the time of
	 * the call (for example because it is involved in a circular reference),
	 * throw a corresponding {@link FactoryBeanNotInitializedException}.
	 * &lt;p&gt;As of Spring 2.0, FactoryBeans are allowed to return {@code null}
	 * objects. The factory will consider this as normal value to be used; it
	 * will not throw a FactoryBeanNotInitializedException in this case anymore.
	 * FactoryBean implementations are encouraged to throw
	 * FactoryBeanNotInitializedException themselves now, as appropriate.
	 * @return an instance of the bean (can be {@code null})
	 * @throws Exception in case of creation errors
	 * @see FactoryBeanNotInitializedException
	 */</span>
	<span class="nd">@Nullable</span>
	<span class="no">T</span> <span class="nf">getObject</span><span class="o">()</span> <span class="kd">throws</span> <span class="nc">Exception</span><span class="o">;</span>

	<span class="cm">/**
	 * Return the type of object that this FactoryBean creates,
	 * or {@code null} if not known in advance.
	 * &lt;p&gt;This allows one to check for specific types of beans without
	 * instantiating objects, for example on autowiring.
	 * &lt;p&gt;In the case of implementations that are creating a singleton object,
	 * this method should try to avoid singleton creation as far as possible;
	 * it should rather estimate the type in advance.
	 * For prototypes, returning a meaningful type here is advisable too.
	 * &lt;p&gt;This method can be called &lt;i&gt;before&lt;/i&gt; this FactoryBean has
	 * been fully initialized. It must not rely on state created during
	 * initialization; of course, it can still use such state if available.
	 * &lt;p&gt;&lt;b&gt;NOTE:&lt;/b&gt; Autowiring will simply ignore FactoryBeans that return
	 * {@code null} here. Therefore it is highly recommended to implement
	 * this method properly, using the current state of the FactoryBean.
	 * @return the type of object that this FactoryBean creates,
	 * or {@code null} if not known at the time of the call
	 * @see ListableBeanFactory#getBeansOfType
	 */</span>
	<span class="nd">@Nullable</span>
	<span class="nc">Class</span><span class="o">&lt;?&gt;</span> <span class="n">getObjectType</span><span class="o">();</span>

	<span class="cm">/**
	 * Is the object managed by this factory a singleton? That is,
	 * will {@link #getObject()} always return the same object
	 * (a reference that can be cached)?
	 * &lt;p&gt;&lt;b&gt;NOTE:&lt;/b&gt; If a FactoryBean indicates to hold a singleton object,
	 * the object returned from {@code getObject()} might get cached
	 * by the owning BeanFactory. Hence, do not return {@code true}
	 * unless the FactoryBean always exposes the same reference.
	 * &lt;p&gt;The singleton status of the FactoryBean itself will generally
	 * be provided by the owning BeanFactory; usually, it has to be
	 * defined as singleton there.
	 * &lt;p&gt;&lt;b&gt;NOTE:&lt;/b&gt; This method returning {@code false} does not
	 * necessarily indicate that returned objects are independent instances.
	 * An implementation of the extended {@link SmartFactoryBean} interface
	 * may explicitly indicate independent instances through its
	 * {@link SmartFactoryBean#isPrototype()} method. Plain {@link FactoryBean}
	 * implementations which do not implement this extended interface are
	 * simply assumed to always return independent instances if the
	 * {@code isSingleton()} implementation returns {@code false}.
	 * &lt;p&gt;The default implementation returns {@code true}, since a
	 * {@code FactoryBean} typically manages a singleton instance.
	 * @return whether the exposed object is a singleton
	 * @see #getObject()
	 * @see SmartFactoryBean#isPrototype()
	 */</span>
	<span class="k">default</span> <span class="kt">boolean</span> <span class="nf">isSingleton</span><span class="o">()</span> <span class="o">{</span>
		<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
	<span class="o">}</span>

<span class="o">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">FactoryBean</code>为工厂<code class="language-plaintext highlighter-rouge">Bean</code>，通过<code class="language-plaintext highlighter-rouge">getObject</code>才会返回实际的<code class="language-plaintext highlighter-rouge">Bean</code>。可以通过它</p>

<p>来构建、自定义<code class="language-plaintext highlighter-rouge">Bean</code>。可以通过<code class="language-plaintext highlighter-rouge">&amp;BeanName</code>获取<code class="language-plaintext highlighter-rouge">FactoryBean</code>本身。</p>

<p>如<code class="language-plaintext highlighter-rouge">Bean</code>初始化逻辑十分复杂，可以使用<code class="language-plaintext highlighter-rouge">FactoryBean</code>来初始化你的<code class="language-plaintext highlighter-rouge">Bean</code>。Mybatis的<code class="language-plaintext highlighter-rouge">SqlSessionFactoryBean</code>就是使用了此拓展点。</p>

<h3 id="beandefinition拓展">BeanDefinition拓展</h3>

<p><code class="language-plaintext highlighter-rouge">init-method()</code>和<code class="language-plaintext highlighter-rouge">destory-method()</code>分别在初始化前和关闭<code class="language-plaintext highlighter-rouge">Bean</code>后调用。</p>

<h2 id="小结">小结</h2>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/190515/spring拓展点执行顺序.png" alt="spring拓展点执行顺序" /></p>

<h2 id="applicationlistener">ApplicationListener</h2>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * Interface to be implemented by application event listeners.
 * Based on the standard {@code java.util.EventListener} interface
 * for the Observer design pattern.
 *
 * &lt;p&gt;As of Spring 3.0, an ApplicationListener can generically declare the event type
 * that it is interested in. When registered with a Spring ApplicationContext, events
 * will be filtered accordingly, with the listener getting invoked for matching event
 * objects only.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @param &lt;E&gt; the specific ApplicationEvent subclass to listen to
 * @see org.springframework.context.event.ApplicationEventMulticaster
 */</span>
<span class="nd">@FunctionalInterface</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">ApplicationListener</span><span class="o">&lt;</span><span class="no">E</span> <span class="kd">extends</span> <span class="nc">ApplicationEvent</span><span class="o">&gt;</span> <span class="kd">extends</span> <span class="nc">EventListener</span> <span class="o">{</span>

   <span class="cm">/**
    * Handle an application event.
    * @param event the event to respond to
    */</span>
   <span class="kt">void</span> <span class="nf">onApplicationEvent</span><span class="o">(</span><span class="no">E</span> <span class="n">event</span><span class="o">);</span>

<span class="o">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">ApplicationEvent</code>事件监听。</p>

<h2 id="参考文献">参考文献</h2>

<p><a href="http://blog.gavinzh.com/2017/11/20/spring-develop-summary/">Spring扩展点总结</a></p>

<p><a href="https://blog.csdn.net/zhaocuit/article/details/83784079">springboot(5)提供的扩展接口</a></p>]]></content><author><name>Kuradeon</name></author><category term="Spring" /><category term="拓展点" /><summary type="html"><![CDATA[Spring 拓展点 定位 ApplicationContextInitializer /** * Callback interface for initializing a Spring {@link ConfigurableApplicationContext} * prior to being {@linkplain ConfigurableApplicationContext#refresh() refreshed}. * * &lt;p&gt;Typically used within web applications that require some programmatic initialization * of the application context. For example, registering property sources or activating * profiles against the {@linkplain ConfigurableApplicationContext#getEnvironment() * context's environment}. See {@code ContextLoader} and {@code FrameworkServlet} support * for declaring a "contextInitializerClasses" context-param and init-param, respectively. * * &lt;p&gt;{@code ApplicationContextInitializer} processors are encouraged to detect * whether Spring's {@link org.springframework.core.Ordered Ordered} interface has been * implemented or if the @{@link org.springframework.core.annotation.Order Order} * annotation is present and to sort instances accordingly if so prior to invocation. * * @author Chris Beams * @since 3.1 * @param &lt;C&gt; the application context type * @see org.springframework.web.context.ContextLoader#customizeContext * @see org.springframework.web.context.ContextLoader#CONTEXT_INITIALIZER_CLASSES_PARAM * @see org.springframework.web.servlet.FrameworkServlet#setContextInitializerClasses * @see org.springframework.web.servlet.FrameworkServlet#applyInitializers */ public interface ApplicationContextInitializer&lt;C extends ConfigurableApplicationContext&gt; { /** * Initialize the given application context. * @param applicationContext the application to configure */ void initialize(C applicationContext); } 在ApplicationContext调用refresh()之前提供回调，如实现自定义路径的资源加载。]]></summary></entry><entry><title type="html">MySQL笔记</title><link href="https://www.kuradeon.cn/2018/12/23/MySQL%E7%AC%94%E8%AE%B0.html" rel="alternate" type="text/html" title="MySQL笔记" /><published>2018-12-23T00:00:00+00:00</published><updated>2018-12-23T00:00:00+00:00</updated><id>https://www.kuradeon.cn/2018/12/23/MySQL%E7%AC%94%E8%AE%B0</id><content type="html" xml:base="https://www.kuradeon.cn/2018/12/23/MySQL%E7%AC%94%E8%AE%B0.html"><![CDATA[<h2 id="mysql体系结构">MySQL体系结构</h2>

<ul>
  <li><strong>Connector</strong>：接入方连接器</li>
  <li><strong>Management Services &amp; Utilities</strong>：系统管理和控制工具，dump、分区管理等</li>
  <li><strong>Connection Pool</strong>：连接池</li>
  <li><strong>Parser</strong>：解析器</li>
  <li><strong>Optimizer</strong>：查询优化器</li>
  <li><strong>Caches &amp; Buffers</strong>：缓存区</li>
  <li><strong>Pluggable Storage Engines</strong>：插件式存储引擎</li>
</ul>

<!--more-->

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/181223/mysql体系.jpg" alt="MySQL体系结构" /></p>

<h3 id="执行顺序">执行顺序</h3>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/181223/MySQL执行顺序.png" alt="MySQL执行顺序" /></p>

<h2 id="存储引擎">存储引擎</h2>

<ul>
  <li>可插拔式：插件式</li>
  <li>表级：可每张表单独配置对应的存储引擎</li>
  <li>不管表使用什么储存引擎，都会生成frm文件，存储表的定义</li>
</ul>

<h3 id="csv">CSV</h3>

<ul>
  <li>不支持索引</li>
  <li>列必须为not null</li>
  <li>不能自增</li>
  <li>数据存储格式为CSV文件，可以直接编辑</li>
</ul>

<h3 id="archive">Archive</h3>

<ul>
  <li>数据文件格式为ARZ</li>
  <li>会对数据进行压缩（zlib）</li>
  <li>只支持insert和select操作</li>
  <li>MySQL 5.5之前不支持索引，5.5之后支持对自增ID列创建索引</li>
  <li>行锁</li>
</ul>

<h3 id="memory">Memory</h3>

<ul>
  <li>数据存储在内存中，服务重启会丢失</li>
  <li>支持hash索引、B- Tree索引</li>
  <li>所有字段长度固定（32），无法使用text、blob等大字段</li>
</ul>

<h3 id="myisam">MyISAM</h3>

<ul>
  <li>MySQL 5.5之前默认引擎</li>
  <li>不支持事务</li>
  <li>不支持外键</li>
  <li>3个表文件（frm：表定义；MYD：数据；MYI：索引）</li>
  <li>非聚集索引</li>
  <li>表锁</li>
  <li>内置统计器统计数据变化，select count不加条件时无需进行数据扫描</li>
</ul>

<h3 id="innodb">InnoDB</h3>

<ul>
  <li>MySQL 5.5之后默认引擎</li>
  <li>支持事务</li>
  <li>行锁</li>
  <li>支持外键</li>
  <li>主键索引：聚集索引；其他索引：非聚集索引</li>
</ul>

<h3 id="对比">对比</h3>

<table>
  <thead>
    <tr>
      <th>功能</th>
      <th>MyISAM</th>
      <th>InnoDB</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>B-tree   索引</td>
      <td>支持</td>
      <td>支持</td>
    </tr>
    <tr>
      <td>索引种类</td>
      <td>非聚集索引</td>
      <td>聚集索引 +   非聚集索引</td>
    </tr>
    <tr>
      <td>数据压缩</td>
      <td>支持</td>
      <td>支持</td>
    </tr>
    <tr>
      <td>数据缓存</td>
      <td>-</td>
      <td>支持</td>
    </tr>
    <tr>
      <td>索引缓存</td>
      <td>支持</td>
      <td>支持</td>
    </tr>
    <tr>
      <td>外键</td>
      <td>-</td>
      <td>支持</td>
    </tr>
    <tr>
      <td>事务</td>
      <td>-</td>
      <td>支持</td>
    </tr>
    <tr>
      <td>锁</td>
      <td>表</td>
      <td>行</td>
    </tr>
    <tr>
      <td>MVCC</td>
      <td>-</td>
      <td>支持</td>
    </tr>
  </tbody>
</table>

<h2 id="索引">索引</h2>

<ul>
  <li>为了加快数据检索效率而存在的数据结构</li>
  <li>可以减少扫描的数据量</li>
  <li>可以将随机IO变为顺序IO</li>
  <li>可以在特定的分组与排序时，避免使用临时表</li>
</ul>

<h3 id="聚集索引">聚集索引</h3>

<p>数据物理存储顺序与键值顺序一致，如InnoDB主键索引</p>

<h3 id="非聚集索引">非聚集索引</h3>

<p>数据存储顺序与键值顺序不一致，如MyiSAM索引，InnoDB非主键索引</p>

<h3 id="innodb索引数据结构">InnoDB索引数据结构</h3>

<h4 id="b树">B+树</h4>

<ul>
  <li>除了根之外的每个节点都包含最少包含[m/2]个元素，最多包含m个元素</li>
  <li>对于任意节点，最多有m个子数</li>
  <li>对于所有非叶子节点，元素数与子树数相等</li>
  <li>所有的叶子节点都在相同的高度上，按顺序排列</li>
</ul>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/181223/B+树.png" alt="B+Tree" /></p>

<h3 id="离散性">离散性</h3>

<p>字段离散性 = select distinct 字段 / select 字段</p>

<p>离散性越大，走索引时效率越高</p>

<h3 id="覆盖索引">覆盖索引</h3>

<p>select 列能通过索引节点中的关键字直接返回</p>

<p>覆盖索引能将随机IO变为顺序IO，提高查询效率</p>

<h3 id="几大原则">几大原则</h3>

<h4 id="最左匹配原则">最左匹配原则</h4>

<p>索引匹配从最左字段开始，直到遇到&lt;,&gt;,&lt;&gt;，like等为止</p>

<h4 id="离散度高原则">离散度高原则</h4>

<p>离散度越大，索引筛选效率越高</p>

<h4 id="最少空间原则">最少空间原则</h4>

<p>创建索引的字段长度越小越好</p>

<h4 id="联合索引优先原则">联合索引优先原则</h4>

<p>联合索引筛选效率优于单值索引</p>

<h3 id="执行计划">执行计划</h3>

<p>Explain + select SQL</p>

<h4 id="怎么查看">怎么查看</h4>

<pre><code class="language-mysql">EXPLAIN select * from table1 where Id in (select table1Id from table2 where table2Id = 1) 

</code></pre>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/181223/执行计划.png" alt="执行计划" /></p>

<h5 id="id">Id</h5>

<p>Id越大，越先执行</p>

<p>Id相同，从上往下执行</p>

<h5 id="select_type">select_type</h5>

<ul>
  <li><strong>SIMPLE</strong>：简单的select，不包含子查询和union</li>
  <li><strong>PRIMARY</strong>：包含子查询或union，最外层查询为primary</li>
  <li><strong>SUBQUERY</strong>：子查询</li>
  <li><strong>MATERIALIZED</strong>：where in 的子查询</li>
  <li><strong>UNION</strong>：union 后的查询</li>
  <li><strong>UNION RESULT</strong>：从union结果中获取数据的select</li>
</ul>

<h5 id="type">Type</h5>

<ul>
  <li><strong>System</strong>：查询系统表</li>
  <li><strong>Const</strong>：走索引一次就找到了</li>
  <li><strong>Eq_ref</strong>：通过唯一索引、主键索引扫描</li>
  <li><strong>Ref</strong>：通过其他索引扫描，返回单一值的情况（=）</li>
  <li><strong>Range</strong>：通过索引扫描，返回一个范围的数据（&lt;&gt;）</li>
  <li><strong>Index</strong>：通过索引全表扫描</li>
  <li><strong>All</strong>：全表扫描</li>
</ul>

<p>执行效率</p>

<p>System &gt; Const &gt; eq_ref &gt; ref&gt; range &gt; index &gt; all</p>

<h5 id="table">Table</h5>

<p>查询表的名称或别名</p>

<h5 id="possible_keys">Possible_keys</h5>

<p>可能用到的索引</p>

<h5 id="key">Key</h5>

<p>实际用的索引</p>

<h5 id="rows">Rows</h5>

<p>大致需要读取的行数</p>

<h5 id="filtered">Filtered</h5>

<p>返回行占rows的百分比</p>

<h5 id="extra">extra</h5>

<ul>
  <li><strong>Using index</strong>：使用了覆盖索引</li>
  <li><strong>Using where</strong>：使用了where过滤</li>
  <li><strong>Using temporary</strong>：使用了临时表</li>
  <li><strong>Using filesort</strong>：使用了外部文件进行排序，没有使用表内的索引</li>
  <li><strong>select tables optimized away</strong>：使用了MyISAM等select count优化或基于索引的min、max优化，直接返回数据</li>
</ul>

<h2 id="事务">事务</h2>

<h3 id="acid">ACID</h3>

<ul>
  <li><strong>原子性Atomicty</strong>：数据修改要么一起成功，要么一起失败</li>
  <li><strong>一致性Consistency</strong>：事务操作的数据变更及状态改变是一致的</li>
  <li><strong>隔离性Isolation</strong>：一个事务的数据在提交前，对其他事务是不可见的</li>
  <li><strong>持久性Durability</strong>：事务所做的变更，提交后将会永久保存</li>
</ul>

<h3 id="隔离级别">隔离级别</h3>

<ul>
  <li><strong>读未提交（Read Ucommitted）</strong>：没提交的事务对其他事务也是可见的，可能遇到脏读（dirty read）</li>
  <li><strong>读提交（Read Committed）</strong>：只能读取自己事务内的修改和其他事务已经提交的修改，可能遇到不可重复读（nonrepeatable read）</li>
  <li><strong>可重复读（Repeatable Read）</strong>：同一事务多次读取同一数据的结果是一样的，可能遇到幻读（phantom read）</li>
  <li><strong>序列化（serializable）</strong>：事务串行执行</li>
</ul>

<h3 id="锁">锁</h3>

<h4 id="共享锁share-lock">共享锁（share lock）</h4>

<p>读锁，多个事务可共享此锁，但是只能读数据，不可修改数据</p>

<p>锁行</p>

<h4 id="排它锁exclusive-lock">排它锁（exclusive lock）</h4>

<p>写锁，不可与其他锁共存，获取排他锁后可以对数据进行读取和修改</p>

<p>锁行</p>

<h4 id="意向共享锁intention-share-lock">意向共享锁（intention share lock）</h4>

<p>当事务想要给数据行加共享锁时，需要先取得此表的意向共享锁；意向共享锁之间是相互共享的</p>

<p>锁表</p>

<h4 id="意向排它锁intention-exclusive-lock">意向排它锁（intention exclusive lock）</h4>

<p>当事务想要给数据行加排他锁时，先要给表加意向排他锁；意向排他锁之间是互相共享的</p>

<p>锁表</p>

<h4 id="自增锁auto-inc-lock">自增锁（auto-inc lock）</h4>

<p>针对自增列加的特殊表锁</p>

<h4 id="记录锁record-lock">记录锁（record lock）</h4>

<p>锁住具体记录的索引项。走索引进行等值匹配，且能匹配到数据时使用</p>

<h4 id="间隙锁gap-lock">间隙锁（gap lock）</h4>

<p>锁住一段区间（左开右开）。走索引检索是，没有匹配到具体的记录时使用，只在RR隔离级别存在</p>

<h4 id="临键锁next-key-lock">临键锁（Next key lock）</h4>

<p>锁住具体记录即一段区间（左开右闭）。走索引进行范围查找，并能找到记录时使用。</p>

<h3 id="多版本并发控制-mvccmultiversion-concurrency-control">多版本并发控制 MVCC（Multiversion concurrency control）</h3>

<p>对事务内处理的数据做多版本管理，避免写操作对读操作的阻塞。</p>

<p>InnoDB MVCC在每张表会添加DB_TRX_ID（数据行事务版本号）、DB_ROLL_PT（数据行删除事务版本号）两个隐藏列</p>

<ul>
  <li>事务开始时，从系统获取事务全局ID</li>
  <li>事务内insert数据的DB_TRX_ID字段为此事务ID</li>
  <li>事务内delete数据的DB_ROLL_PT字段修改为此事务ID</li>
  <li>事务内update的数据，将老数据的DB_ROLL_PT字段修改为此事务ID；Copy一条新数据出来，DB_TRX_ID字段为此事物ID</li>
  <li>事务内查询的数据为DB_TRX_ID比当前事务ID小的数据 + DB_ROLL_PT为null或比当前事务ID大的数据</li>
</ul>

<h2 id="日志">日志</h2>

<h3 id="redo-log">Redo log</h3>

<p>记录事务操作的最新数据，用来实现持久化</p>

<h3 id="uodo-log">Uodo log</h3>

<p>记录事务操作前的数据，用来实现原子性</p>

<h3 id="bin-log">Bin log</h3>

<p>记录会改变数据的操作日志，常用来做主从同步</p>

<h3 id="error-log">Error log</h3>

<p>记录mysql服务的错误日志</p>

<h3 id="general-log">General log</h3>

<p>记录客户端执行的sql语句</p>

<h3 id="show-log">Show log</h3>

<p>记录慢查询和没走索引的sql</p>

<h3 id="relay-log">Relay log</h3>

<p>中继日志，常与bin log配合来做主从同步</p>]]></content><author><name>Kuradeon</name></author><category term="MySQL" /><category term="事务" /><category term="锁" /><summary type="html"><![CDATA[MySQL体系结构 Connector：接入方连接器 Management Services &amp; Utilities：系统管理和控制工具，dump、分区管理等 Connection Pool：连接池 Parser：解析器 Optimizer：查询优化器 Caches &amp; Buffers：缓存区 Pluggable Storage Engines：插件式存储引擎]]></summary></entry><entry><title type="html">JVM深入浅出</title><link href="https://www.kuradeon.cn/2018/08/10/JVM%E6%B7%B1%E5%85%A5%E6%B5%85%E5%87%BA.html" rel="alternate" type="text/html" title="JVM深入浅出" /><published>2018-08-10T00:00:00+00:00</published><updated>2018-08-10T00:00:00+00:00</updated><id>https://www.kuradeon.cn/2018/08/10/JVM%E6%B7%B1%E5%85%A5%E6%B5%85%E5%87%BA</id><content type="html" xml:base="https://www.kuradeon.cn/2018/08/10/JVM%E6%B7%B1%E5%85%A5%E6%B5%85%E5%87%BA.html"><![CDATA[<h2 id="jvm简介">JVM简介</h2>

<blockquote>
  <p>•JVM是Java Virtual Machine（Java<a href="https://baike.baidu.com/item/%E8%99%9A%E6%8B%9F%E6%9C%BA">虚拟机</a>）的缩写，JVM是一种用于计算设备的规范，它是一个虚构出来的计算机，是通过在实际的计算机上仿真模拟各种计算机功能来实现的。</p>

  <p>•<a href="https://baike.baidu.com/item/Java%E8%AF%AD%E8%A8%80">Java</a><a href="https://baike.baidu.com/item/Java%E8%AF%AD%E8%A8%80">语言</a>的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行，至少需要编译成不同的<a href="https://baike.baidu.com/item/%E7%9B%AE%E6%A0%87%E4%BB%A3%E7%A0%81/9407934">目标代码</a>。而引入Java语言虚拟机后，Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息，使得Java语言<a href="https://baike.baidu.com/item/%E7%BC%96%E8%AF%91%E7%A8%8B%E5%BA%8F/8290180">编译程序</a>只需生成在Java虚拟机上运行的目标代码（<a href="https://baike.baidu.com/item/%E5%AD%97%E8%8A%82%E7%A0%81/9953683">字节码</a>），就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时，把字节码解释成具体平台上的<a href="https://baike.baidu.com/item/%E6%9C%BA%E5%99%A8%E6%8C%87%E4%BB%A4/8553126">机器指令</a>执行。这就是Java的能够“一次编译，到处运行”的原因。</p>
</blockquote>

<!--more-->

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180810/iaihaAkJGk.png" alt="iaihaAkJGk" /></p>

<h2 id="jmmjava-memory-model">JMM（Java Memory Model）</h2>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180810/0eJ3FcEbhd.png" alt="0eJ3FcEbhd" /></p>

<blockquote>
  <p>JDK 1.7 之前，方法区实现为永久代；JDK 1.8 后，使用Meta Space（元空间代替）</p>
</blockquote>

<h3 id="程序计数器pc">程序计数器（PC）</h3>

<blockquote>
  <ul>
    <li>
      <p>每个线程都会有自己私有的程序计数器(PC)。可以看作是当前线程所执行的字节码的行号指示器。</p>
    </li>
    <li>可以理解为下一条将要执行的指令的地址或者行号。字节码解释器就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。分支、循环、 跳转、异常处理、上下文切换等，都要依赖PC。</li>
    <li>执行Java 方法 – PC指向正在执行的虚拟机字节码指令地址</li>
    <li>执行Native方法 – PC 为空。</li>
  </ul>
</blockquote>

<h3 id="虚拟机栈vm-stack">虚拟机栈（VM Stack）</h3>

<blockquote>
  <ul>
    <li>Java方法执行时的字典：记录局部变量表、操作数栈、动态链接、方法出口等信息。</li>
    <li>栈帧（ Frame）
      <ul>
        <li>Java虚拟机栈的存储结构，是用来存储数据和部分过程结果的数据结构，同时也被用来处理动态链接 (Dynamic Linking)、 方法返回值和异常分派（ Dispatch Exception）。 </li>
        <li>每一个栈帧都有自己的局部变量表（ Local Variables）、操作数栈（ OperandStack）和指向当前方法所属的类的运行时常量池的引用，随着方法调用而创建，随着方法结束而销毁。
          <ul>
            <li>局部变量表：是一组变量值存储空间，用于存放方法参数和方法内部定义的局部变量。在Java程序被编译为Class文件时，就在方法的Code属性的max_locals数据项中确定了方法所需要分配的最大局部变量表的容量。</li>
            <li>操作数栈：还包含一个后进先出（Last-In-First-Out）的，也可以称之为表达式栈（Expression Stack），用于协助执行运算，如加减乘除。</li>
            <li>动态链接：就是不对那些组成程序的<a href="https://baike.baidu.com/item/%E7%9B%AE%E6%A0%87%E6%96%87%E4%BB%B6">目标文件</a>进行链接，等到程序要运行时才进行链接。也就是说，把链接这个过程推迟到了运行时再进行，这就是<a href="https://baike.baidu.com/item/%E5%8A%A8%E6%80%81%E9%93%BE%E6%8E%A5">动态链接</a>(Dynamic Linking) 。</li>
            <li>方法出口：方法返回值等</li>
          </ul>
        </li>
      </ul>
    </li>
  </ul>
</blockquote>

<h3 id="本地方法栈native-method-stack">本地方法栈（Native Method Stack）</h3>

<blockquote>
  <ul>
    <li>VM Stack是为执行Java方法服务的，此处的Native Method Stack是为执行本地方法服务的，有的虚拟机(比如 HotSpot )将VM Stack和Native Method Stack合二为一</li>
  </ul>
</blockquote>

<h3 id="堆heap">堆（Heap）</h3>

<blockquote>
  <ul>
    <li>所有线程共享的内存区域，存储了被自动内存管理系统所管理的各种对象 </li>
    <li>包括年轻代、老年代</li>
  </ul>
</blockquote>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180810/lB0BaAlHFg.png" alt="lB0BaAlHFg" /></p>

<h4 id="年轻代young">年轻代（Young）</h4>

<blockquote>
  <ul>
    <li>存放new 出来的对象</li>
    <li>划分为三部分，Eden区和两个大小严格相同的Survivor区，其中Survivor区间中，某一时刻只有其中一个是被使用的，另外一个留做垃圾收集时复制对象用，在Young区间变满的时候，minor GC就会将存活的对象移到空闲的Survivor区间中。经过几次垃圾收集后，任然存活于Survivor的对象将被移动到Old区间。</li>
  </ul>
</blockquote>

<p>####老年代（Old）</p>

<blockquote>
  <ul>
    <li>保存生命周期长的对象，当一些对象在Young复制转移一定的次数以后，对象就会被转移到Old区</li>
  </ul>
</blockquote>

<h3 id="方法区method-area">方法区（Method Area）</h3>

<blockquote>
  <ul>
    <li>所有线程共享的内存区域</li>
    <li>存放Class信息、静态变量、常量等</li>
    <li>JDK 1.8 后，被Meta Space（元空间）代替</li>
  </ul>
</blockquote>

<h3 id="元空间meta-space">元空间（Meta Space）</h3>

<blockquote>
  <ul>
    <li>JDK 1.8 后引入，代替永久代。</li>
    <li>Meta Space 在Native Memory中，可以无限扩容（可以通过参数限制大小），解决java.lang.OutOfMemoryError : PermGen space 问题。</li>
  </ul>
</blockquote>

<h2 id="gc-介绍">GC 介绍</h2>

<h3 id="minor-gc">Minor GC</h3>

<blockquote>
  <p>年轻代GC</p>

  <ol>
    <li>回收Eden区对象，将遗留下来的对象放入Survivor区；</li>
    <li>将Survivor区对象整理后，放入另一半Survivor区；</li>
    <li>当Survivor区中对象超过年龄，将之放入Old区；</li>
    <li>当Survivor区中对象空间超过Survivor区一半大小时，将对象放入Old区。</li>
  </ol>
</blockquote>

<h3 id="major-gc">Major GC</h3>

<blockquote>
  <p>老年代GC，通常由Young GC 触发，不会单独运行</p>

  <ol>
    <li>清除老年代中对象；</li>
    <li>清除方法区（JDK 1.7 -）或元空间（JDK 1.8 + ）中的对象。</li>
  </ol>
</blockquote>

<h3 id="full-gc">Full GC</h3>

<blockquote>
  <p>Minor GC + Major GC</p>
</blockquote>

<h3 id="判断对象是否需要回收">判断对象是否需要回收</h3>

<h4 id="引用计数">引用计数</h4>

<blockquote>
  <ul>
    <li>引用计数存储对特定对象的所有引用数，也就是说，当应用程序创建引用以及引用超出范围时，JVM 必须增减引用数。当某对象的引用数为0时，便可以进行垃圾收集。</li>
  </ul>
</blockquote>

<h4 id="可达性分析">可达性分析</h4>

<blockquote>
  <ul>
    <li>对象引用从GC Root开始遍历，沿着对象引用链，递归确定可到达（reachable）的对象。如果某对象不能从这些GC Root的至少一个到达，则将它作为垃圾收集。</li>
    <li>如下图，e、f、g、h、i，将被回收。</li>
  </ul>
</blockquote>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180810/HdDiiG22FA.png" alt="HdDiiG22FA" /></p>

<h3 id="gc-算法">GC 算法</h3>

<h4 id="标记-清除-算法">标记-清除 算法</h4>

<blockquote>
  <p>分为2个步骤：</p>

  <ol>
    <li>标记：标记的过程其实就是，遍历所有的GC Root，然后将所有GC Root可达的对象标记为存活的对象。</li>
    <li>清除：清除的过程将遍历堆中所有的对象，将没有标记的对象全部清除掉。</li>
  </ol>
</blockquote>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180810/Hg3gd58ff4.png" alt="Hg3gd58ff4" /></p>

<h4 id="复制-算法">复制 算法</h4>

<blockquote>
  <ul>
    <li>将内存划分为两个区间，在任意时间点，所有动态分配的对象都只能分配在其中一个区间（称为活动区间），而另外一个区间（称为空闲区间）则是空闲的</li>
    <li>GC发生时，将活动区间内的存活对象，全部复制到空闲区间，且严格按照内存地址依次排列，并将存活对象的内存引用地址指向新的内存地址。</li>
  </ul>
</blockquote>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180810/dDHaDkkK8B.png" alt="dDHaDkkK8B" /></p>

<h4 id="标记-整理-算法">标记-整理 算法</h4>

<blockquote>
  <p>分为两个步骤：</p>

  <ol>
    <li>标记：它的第一个阶段与标记-清除算法是一模一样的，均是遍历GC Root，然后将存活的对象标记。</li>
    <li>整理：移动所有存活的对象，且按照内存地址次序依次排列，然后将末端内存地址以后的内存全部回收。</li>
  </ol>
</blockquote>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180810/KeKHgjF3i1.png" alt="KeKHgjF3i1" /></p>

<h3 id="gc-收集器">GC 收集器</h3>

<h4 id="分代收集">分代收集</h4>

<blockquote>
  <p>把Heap 分为年轻代和老年代，根据各自的特点采用不同的、合适的算法。</p>
</blockquote>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180810/KF8B5099gG.png" alt="KF8B5099gG" /></p>

<h4 id="serial-收集器">Serial 收集器</h4>

<blockquote>
  <ul>
    <li>串行收集器是最古老，最稳定以及效率高的收集器，可能会产生较长的停顿，只使用一个线程去回收。新生代、老年代使用串行回收。</li>
    <li>新生代复制算法、老年代标记-整理；</li>
    <li>垃圾收集的过程中会Stop The World（服务暂停）。</li>
  </ul>
</blockquote>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180810/amiHebf1Gb.png" alt="amiHebf1Gb" /></p>

<h4 id="parnew-收集器">ParNew 收集器</h4>

<blockquote>
  <ul>
    <li>ParNew收集器其实就是Serial 收集器的多线程版本。</li>
    <li>新生代并行，采用复制算法；</li>
    <li>垃圾收集的过程中会STW。</li>
  </ul>
</blockquote>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180810/HCFhbb6D5h.png" alt="HCFhbb6D5h" /></p>

<h4 id="parallel-收集器">Parallel 收集器</h4>

<blockquote>
  <ul>
    <li>和ParNew 收集器类似，但更关注吞吐量。</li>
    <li>可以通过参数来打开自适应调节策略，虚拟机会根据当前系统的运行情况收集性能监控信息，动态调整这些参数以提供最合适的停顿时间或最大的吞吐量；也可以通过参数控制GC的时间不大于多少毫秒或者比例</li>
    <li>新生代并行，复制算法；老年代采用标记-整理 算法;</li>
    <li>垃圾收集的过程中会STW。</li>
  </ul>
</blockquote>

<h4 id="cms-收集器">CMS 收集器</h4>

<blockquote>
  <ul>
    <li>以最短回收停顿时间为目标的收集器，包括5个步骤
      <ol>
        <li>初始标记（CMS Initial Mark）：标记一下GC Root 能直接关联到的对象，速度很快，期间STW；</li>
        <li>并发标记（CMS Concurrent Mark）：进行GC Root 遍历，找到所有可达对象；</li>
        <li>重新标记（CMS Remark）：修正并发标记期间，因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录，期间STW；</li>
        <li>并发清除（CMS Concurrent Sweep）：清除不可达对象</li>
        <li>并发重置（CMS Concurrent Reset）：重置CMS收集器的数据结构，等待下一次垃圾回收.</li>
      </ol>
    </li>
    <li>老年代使用，采用标记-清除 算法</li>
  </ul>
</blockquote>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180810/LJ5B8bB5IC.png" alt="LJ5B8bB5IC" /></p>

<h4 id="g1-收集器">G1 收集器</h4>

<blockquote>
  <ul>
    <li>G1 是目前技术发展的最前沿成果之一，HotSpot 开发团队赋予它的使命是未来可以替换掉JDK 1.5 中发布的CMS 收集器。与CMS 收集器相比G1 收集器有以下特点：
      <ol>
        <li>空间整合，G1收集器采用标记-整理 算法，不会产生内存空间碎片。分配大对象时不会因为无法找到连续空间而提前触发下一次GC。</li>
        <li>可预测停顿，这是G1的另一大优势，降低停顿时间是G1和CMS的共同关注点，但G1除了追求低停顿外，还能建立可预测的停顿时间模型，能让使用者明确指定在一个长度为N毫秒的时间片段内，消耗在垃圾收集上的时间不得超过N毫秒，这几乎已经是实时Java（RTSJ）的垃圾收集器的特征了。</li>
      </ol>
    </li>
    <li>使用G1收集器时，整个Java堆划分为多个大小相等的独立区域（Region），虽然还保留有新生代和老年代的概念，但新生代和老年代不再是物理隔阂了，它们都是一部分（可以不连续）Region的集合。</li>
  </ul>
</blockquote>

<p><a href="http://blog.jobbole.com/109170/">G1 收集器介绍</a></p>

<p><a href="https://tech.meituan.com/2016/09/23/g1.html">Java Hotspot G1 GC的一些关键技术</a></p>

<h2 id="内存分配策略">内存分配策略</h2>

<blockquote>
  <p><strong>优先在TLAB（Thread Local Allocation Buffer 线程本地分配缓冲）中分配</strong></p>

  <p><strong>在Eden分配</strong></p>

  <p><strong>大对象直接进入老年代</strong>：-XX:PretenureSizeThreshold参数可以配置</p>

  <p><strong>长期存活的对象进入老年代</strong>：-XX:MaxTenuringThreshold可以配置年龄</p>

  <p><strong>动态对象年龄判定</strong>：有的虚拟机不一定需要对象的年龄达到MaxTeruringThreshold才能晋升老年代。如果在Survivor空间中相同年龄所有对象大小的总和大于Surivior空间的一半，年龄大于或等于该年龄的对象就可以直接进行老年代。</p>

  <p><strong>空间分配担保</strong>：在发生Minor GC之前，虚拟机会先检查老年代中最大的可用的连续空间是否大于新生代中所有对象总空间，如果这个条件成立，那么Minor GC可以确保是安全的。</p>

  <p>如果不成立，则虚拟机会查看HandlePromotionFaiure设置值是否允许担保失败。如果允许，那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小，如果大于，将尝试进行一次Minor GC，尽管这次GC是有风险的；如果小于，或者HandlePromotionFaiure设置不允许冒险，那么这时就要改为进行一次Full GC。</p>
</blockquote>

<h2 id="gc-发生条件">GC 发生条件</h2>

<p>###Minor GC</p>

<blockquote>
  <p>JVM 无法为新对象分配内存空间，比如Eden区满了</p>
</blockquote>

<p>###Full GC</p>

<blockquote>
  <ul>
    <li>方法区空间不足：Full GC之后永久代空间还是不足，系统就抛出：java.lang.OutOfMemoryError: PermGen space异常（1.7及以下）</li>
    <li>老年代空间不足：Minor GC 后进去老年代的空间大小 &gt; 老年代剩余空间大小。如果进行FullGC后老年代依然无法容纳转入对象，那么系统就会抛出：java.lang.OutOfMemoryError: Java heap space异常。</li>
    <li>空间担保失败</li>
    <li>调用System.gc</li>
    <li>promotion failed：Minor GC时，新生代中的对象从Eden区往survivor区转移，但是survivor区放不下，只能放入老年代，但是老年代也放不下，这时就会出现promotion failed的情况，触发Full GC。</li>
    <li>concurrent mode failure：CMS GC过程中将对象放入老年代，但是老年代空间不足。</li>
  </ul>
</blockquote>

<h2 id="jvm-调优">JVM 调优</h2>

<h3 id="gc-算法组合">GC 算法组合</h3>

<table>
  <thead>
    <tr>
      <th>新生代GC策略</th>
      <th>年老代GC策略</th>
      <th>说明</th>
      <th> </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>组合1</td>
      <td>Serial</td>
      <td>Serial   Old</td>
      <td>Serial和Serial   Old都是单线程进行GC，特点就是GC时暂停所有应用线程。</td>
    </tr>
    <tr>
      <td>组合2</td>
      <td>Serial</td>
      <td>CMS+Serial   Old</td>
      <td>CMS（Concurrent   Mark Sweep）是并发GC，实现GC线程和应用线程并发工作，不需要暂停所有应用线程。另外，当CMS进行GC失败时，会自动使用Serial   Old策略进行GC。</td>
    </tr>
    <tr>
      <td>组合3</td>
      <td>ParNew</td>
      <td>CMS</td>
      <td>使用-XX:+UseParNewGC选项来开启。ParNew是Serial的并行版本，可以指定GC线程数，默认GC线程数为CPU的数量。可以使用-XX:ParallelGCThreads选项指定GC的线程数。   如果指定了选项-XX:+UseConcMarkSweepGC选项，则新生代默认使用ParNew   GC策略。</td>
    </tr>
    <tr>
      <td>组合4</td>
      <td>ParNew</td>
      <td>Serial   Old</td>
      <td>使用-XX:+UseParNewGC选项来开启。新生代使用ParNew   GC策略，年老代默认使用Serial Old GC策略。</td>
    </tr>
    <tr>
      <td>组合5</td>
      <td>Parallel   Scavenge</td>
      <td>Serial   Old</td>
      <td>Parallel   Scavenge策略主要是关注一个可控的吞吐量：应用程序运行时间 /   (应用程序运行时间 + GC时间)，可见这会使得CPU的利用率尽可能的高，适用于后台持久运行的应用程序，而不适用于交互较多的应用程序。</td>
    </tr>
    <tr>
      <td>组合6</td>
      <td>Parallel   Scavenge</td>
      <td>Parallel   Old</td>
      <td>Parallel   Old是Serial Old的并行版本</td>
    </tr>
    <tr>
      <td>组合7</td>
      <td>G1GC</td>
      <td>G1GC</td>
      <td>-XX:+UnlockExperimentalVMOptions   -XX:+UseG1GC        #开启      -XX:MaxGCPauseMillis   =50                  #暂停时间目标      -XX:GCPauseIntervalMillis   =200          #暂停间隔目标      -XX:+G1YoungGenSize=512m            #年轻代大小      -XX:SurvivorRatio=6                            #幸存区比例</td>
    </tr>
  </tbody>
</table>

<h3 id="详细jvm-参数">详细JVM 参数</h3>

<p><a href="http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html">JVM 参数</a></p>

<h2 id="参考文献">参考文献</h2>

<blockquote>
  <p>http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html</p>

  <p><a href="https://blog.csdn.net/hylexus/article/details/53564865">https://</a><a href="https://blog.csdn.net/hylexus/article/details/53564865">blog.csdn.net/hylexus/article/details/53564865</a></p>

  <p><a href="https://www.cnblogs.com/ityouknow/p/5614961.html">https://</a><a href="https://www.cnblogs.com/ityouknow/p/5614961.html">www.cnblogs.com/ityouknow/p/5614961.html</a></p>

  <p><a href="https://www.cnblogs.com/ityouknow/p/5614961.html">https://</a><a href="https://www.cnblogs.com/ityouknow/p/5614961.html">www.cnblogs.com/ityouknow/p/5614961.html</a></p>

  <p><a href="https://blog.csdn.net/wfh6732/article/details/57490195?utm_source=itdadao&amp;utm_medium=referral">https://</a><a href="https://blog.csdn.net/wfh6732/article/details/57490195?utm_source=itdadao&amp;utm_medium=referral">blog.csdn.net/wfh6732/article/details/57490195?utm_source=itdadao&amp;utm_medium=referra</a></p>

  <p>https://blog.csdn.net/yhyr_ycy/article/details/52566105</p>

  <p><a href="http://fengfu.io/2016/03/08/JVM触发FullGC的情况总结/">http://fengfu.io/2016/03/08/JVM%E8%A7%A6%E5%8F%91FullGC%E7%9A%84%E6%83%85%E5%86%B5%E6%80%BB%E7%BB%93/</a></p>

  <p>https://www.cnblogs.com/zhouyuqin/p/5164672.html</p>

  <p>《深入理解Java虚拟机》</p>
</blockquote>]]></content><author><name>Kuradeon</name></author><category term="JVM" /><category term="面试" /><category term="GC" /><summary type="html"><![CDATA[JVM简介 •JVM是Java Virtual Machine（Java虚拟机）的缩写，JVM是一种用于计算设备的规范，它是一个虚构出来的计算机，是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 •Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行，至少需要编译成不同的目标代码。而引入Java语言虚拟机后，Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息，使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码（字节码），就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时，把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译，到处运行”的原因。]]></summary></entry><entry><title type="html">Java面试通关要点汇总集基础篇</title><link href="https://www.kuradeon.cn/2018/03/30/Java%E9%9D%A2%E8%AF%95%E9%80%9A%E5%85%B3%E8%A6%81%E7%82%B9%E6%B1%87%E6%80%BB%E9%9B%86%E5%9F%BA%E7%A1%80%E7%AF%87.html" rel="alternate" type="text/html" title="Java面试通关要点汇总集基础篇" /><published>2018-03-30T00:00:00+00:00</published><updated>2018-03-30T00:00:00+00:00</updated><id>https://www.kuradeon.cn/2018/03/30/Java%E9%9D%A2%E8%AF%95%E9%80%9A%E5%85%B3%E8%A6%81%E7%82%B9%E6%B1%87%E6%80%BB%E9%9B%86%E5%9F%BA%E7%A1%80%E7%AF%87</id><content type="html" xml:base="https://www.kuradeon.cn/2018/03/30/Java%E9%9D%A2%E8%AF%95%E9%80%9A%E5%85%B3%E8%A6%81%E7%82%B9%E6%B1%87%E6%80%BB%E9%9B%86%E5%9F%BA%E7%A1%80%E7%AF%87.html"><![CDATA[<h2 id="基础篇">基础篇</h2>

<h3 id="基本功">基本功</h3>

<h4 id="面向对象的特征">面向对象的特征</h4>

<blockquote>
  <p>面向对象的三个基本特征是：封装、继承、多态。
<strong>封装</strong>
封装最好理解了。封装是面向对象的特征之一，是对象和类概念的主要特性。
封装，也就是把客观事物封装成抽象的类，并且类可以把自己的数据和方法只让可信的类或者对象操作，对不可信的进行信息隐藏。
<strong>继承</strong>
面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力：它可以使用现有类的所有功能，并在无需重新编写原来的类的情况下对这些功能进行扩展。
<strong>多态</strong>
多态性（polymorphisn）是允许你将父对象设置成为和一个或更多的他的子对象相等的技术，赋值之后，父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说，就是一句话：允许将子类类型的指针赋值给父类类型的指针。
实现多态，有二种方式，覆盖，重载。</p>
</blockquote>

<!--more-->

<h4 id="final-finally-finalize-的区别">final, finally, finalize 的区别</h4>

<blockquote>
  <p>final 用于声明属性,方法和类, 分别表示属性不可变, 方法不可覆盖, 类不可继承.
finally 是异常处理语句结构的一部分，表示总是执行.
finalize 是Object类的一个方法，在垃圾收集器执行的时候会调用被回收对象的此方法，可以覆盖此方法提供垃圾收集时的其他资源回收，例如关闭文件等. JVM不保证此方法总被调用.</p>
</blockquote>

<h4 id="int-和-integer-有什么区别">int 和 Integer 有什么区别</h4>

<blockquote>
  <p>链接：<a href="https://www.nowcoder.com/questionTerminal/aad1b52a4d98454da9d1d66d0c243a49">https://www.nowcoder.com/questionTerminal/aad1b52a4d98454da9d1d66d0c243a49</a>
来源：牛客网
int是java提供的8种原始数据类型之一。Java为每个原始类型提供了封装类，Integer是java为int提供的封装类。
int的默认值为0，而Integer的默认值为null，是引用类型，即Integer可以区分出未赋值和值为0的区别，int则无法表达出未赋值的情况，
Java中int和Integer关系是比较微妙的。关系如下：</p>

  <ol>
    <li>int是基本的数据类型；</li>
    <li>Integer是int的封装类；</li>
    <li>int和Integer都可以表示某一个数值；</li>
    <li>int和Integer不能够互用，因为他们两种不同的数据类型；</li>
  </ol>
</blockquote>

<h4 id="重载和重写的区别">重载和重写的区别</h4>

<blockquote>
  <p>重载 Overload 表示同一个类中可以有多个名称相同的方法，但这些方法的参数列表各不相同（即参数个数或类型不同）。
重写 Override 表示子类中的方法可以与父类中的某个方法的名称和参数完全相同，通过子类创建的实例对象调用这个方法时，将调用子类中的定义方法，这相当于把父类中定义的那个完全相同的方法给覆盖了，这也是面向对象编程的多态性的一种表现。子类覆盖父类的方法时，只能比父类抛出更少的异常，或者是抛出父类抛出的异常的子异常，因为子类可以解决父类的一些问题，不能比父类有更多的问题。子类方法的访问权限只能比父类的更大，不能更小。如果父类的方法是private类型，那么，子类则不存在覆盖的限制，相当于子类中增加了一个全新的方法。
作者：天天向上
链接：<a href="https://www.zhihu.com/question/35874324/answer/144589616">https://www.zhihu.com/question/35874324/answer/144589616</a>
来源：知乎
著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。</p>
</blockquote>

<h4 id="抽象类和接口有什么区别">抽象类和接口有什么区别</h4>

<table>
  <thead>
    <tr>
      <th><strong>参数</strong></th>
      <th><strong>抽象类</strong></th>
      <th><strong>接口</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>默认的方法实现</td>
      <td>它可以有默认的方法实现</td>
      <td>接口完全是抽象的。它根本不存在方法的实现</td>
    </tr>
    <tr>
      <td>实现</td>
      <td>子类使用<strong>extends</strong>关键字来继承抽象类。如果子类不是抽象类的话，它需要提供抽象类中所有声明的方法的实现。</td>
      <td>子类使用关键字<strong>implements</strong>来实现接口。它需要提供接口中所有声明的方法的实现</td>
    </tr>
    <tr>
      <td>构造器</td>
      <td>抽象类可以有构造器</td>
      <td>接口不能有构造器</td>
    </tr>
    <tr>
      <td>与正常Java类的区别</td>
      <td>除了你不能实例化抽象类之外，它和普通Java类没有任何区别</td>
      <td>接口是完全不同的类型</td>
    </tr>
    <tr>
      <td>访问修饰符</td>
      <td>抽象方法可以有<strong>public</strong>、<strong>protected</strong>和<strong>default</strong>这些修饰符</td>
      <td>接口方法默认修饰符是<strong>public</strong>。你不可以使用其它修饰符。</td>
    </tr>
    <tr>
      <td>main方法</td>
      <td>抽象方法可以有main方法并且我们可以运行它</td>
      <td>接口没有main方法，因此我们不能运行它。</td>
    </tr>
    <tr>
      <td>多继承</td>
      <td>抽象方法可以继承一个类和实现多个接口</td>
      <td>接口只可以继承一个或多个其它接口</td>
    </tr>
    <tr>
      <td>速度</td>
      <td>它比接口速度要快</td>
      <td>接口是稍微有点慢的，因为它需要时间去寻找在类中实现的方法。</td>
    </tr>
    <tr>
      <td>添加新方法</td>
      <td>如果你往抽象类中添加新的方法，你可以给它提供默认的实现。因此你不需要改变你现在的代码。</td>
      <td>如果你往接口中添加方法，那么你必须改变实现该接口的类。</td>
    </tr>
  </tbody>
</table>

<h4 id="说说反射的用途及实现">说说反射的用途及实现</h4>

<blockquote>
  <p>Java反射机制是一个非常强大的功能，在很多的项目比如Spring，Mybatis都都可以看到反射的身影。通过反射机制，我们可以在运行期间获取对象的类型信息。利用这一点我们可以实现工厂模式和代理模式等设计模式，同时也可以解决java泛型擦除等令人苦恼的问题。
获取一个对象对应的反射类，在Java中有三种方法可以获取一个对象的反射类，
通过getClass()方法
通过Class.forName()方法；
使用类.class
通过类加载器实现，getClassLoader()</p>
</blockquote>

<h4 id="说说自定义注解的场景及实现">说说自定义注解的场景及实现</h4>

<blockquote>
  <p>登陆、权限拦截、日志处理，以及各种Java框架，如Spring，Hibernate，JUnit 提到注解就不能不说反射，Java自定义注解是通过运行时靠反射获取注解。实际开发中，例如我们要获取某个方法的调用日志，可以通过AOP（动态代理机制）给方法添加切面，通过反射来获取方法包含的注解，如果包含日志注解，就进行日志记录。反射的实现在 Java 应用层面上讲，是通过对 Class 对象的操作实现的，Class 对象为我们提供了一系列方法对类进行操作。在 Jvm 这个角度来说，Class 文件是一组以 8 位字节为基础单位的二进制流，各个数据项目按严格的顺序紧凑的排列在 Class 文件中，里面包含了类、方法、字段等等相关数据。通过对 Claas 数据流的处理我们即可得到字段、方法等数据。
作者：LeopPro
链接：<a href="https://juejin.im/post/5a9fad016fb9a028b77a5ce9">https://juejin.im/post/5a9fad016fb9a028b77a5ce9</a>
来源：掘金
著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。</p>
</blockquote>

<h4 id="http-请求的-get-与-post-方式的区别">HTTP 请求的 GET 与 POST 方式的区别</h4>

<blockquote>
  <ol>
    <li>根据HTTP规范，GET用于信息获取，而且应该是安全的和幂等的。</li>
    <li>根据HTTP规范，POST表示可能修改变服务器上的资源的请求。</li>
    <li>首先是”GET方式提交的数据最多只能是1024字节”，因为GET是通过URL提交数据，那么GET可提交的数量就跟URL的长度有直接关系了。而实际上，URL不存在参数上限的问题，HTTP协议规范没有对URL长度进行限制。这个限制是特定的浏览器及服务器对它的限制。IE对URL长度的限制是2083字节(2K+35)。对于其他浏览器，如Netscape、FireFox等，理论上没有长度限制，其限制取决于操作系统的支持。注意这是限制是整个URL长度，而不仅仅是你的参数值数据长度。</li>
    <li>POST是没有大小限制的，HTTP协议规范也没有进行大小限制</li>
  </ol>
</blockquote>

<h4 id="session-与-cookie-区别">session 与 cookie 区别</h4>

<blockquote>
  <ol>
    <li>cookie数据存放在客户的浏览器上，session数据放在服务器上。</li>
    <li>cookie不是很安全，别人可以分析存放在本地的COOKIE并进行COOKIE欺骗</li>
  </ol>

  <p>考虑到安全应当使用session。</p>

  <ol>
    <li>
      <p>session会在一定时间内保存在服务器上。当访问增多，会比较占用你服务器的性能。考虑到减轻服务器性能方面，应当使用COOKIE。</p>
    </li>
    <li>
      <p>单个cookie保存的数据不能超过4K，很多浏览器都限制一个站点最多保存20个cookie。</p>
    </li>
    <li>
      <p>所以个人建议：</p>

      <p>将登陆信息等重要信息存放为SESSION</p>

      <p>其他信息如果需要保留，可以放在COOKIE中</p>
    </li>
  </ol>
</blockquote>

<h4 id="session-分布式处理">session 分布式处理</h4>

<blockquote>
  <ol>
    <li>
      <p>Session复制</p>

      <p>在支持Session复制的Web服务器上，通过修改Web服务器的配置，可以实现将Session同步到其它Web服务器上，达到每个Web服务器上都保存一致的Session。</p>

      <p>优点：代码上不需要做支持和修改。</p>

      <p>缺点：需要依赖支持的Web服务器，一旦更换成不支持的Web服务器就不能使用了，在数据量很大的情况下不仅占用网络资源，而且会导致延迟。</p>

      <p>适用场景：只适用于Web服务器比较少且Session数据量少的情况。</p>

      <p>可用方案：开源方案tomcat-redis-session-manager，暂不支持Tomcat8。</p>
    </li>
    <li>
      <p>Session粘滞</p>

      <p>将用户的每次请求都通过某种方法强制分发到某一个Web服务器上，只要这个Web服务器上存储了对应Session数据，就可以实现会话跟踪。
优点：使用简单，没有额外开销。
缺点：一旦某个Web服务器重启或宕机，相对应的Session数据将会丢失，而且需要依赖负载均衡机制。
适用场景：对稳定性要求不是很高的业务情景。</p>
    </li>
    <li>
      <p>Session集中管理</p>

      <p>在单独的服务器或服务器集群上使用缓存技术，如Redis存储Session数据，集中管理所有的Session，所有的Web服务器都从这个存储介质中存取对应的Session，实现Session共享。
优点：可靠性高，减少Web服务器的资源开销。
缺点：实现上有些复杂，配置较多。
适用场景：Web服务器较多、要求高可用性的情况。
可用方案：开源方案Spring Session，也可以自己实现，主要是重写HttpServletRequestWrapper中的getSession方法，博主也动手写了一个，github搜索joincat用户，然后自取。</p>
    </li>
    <li>
      <p>基于Cookie管理</p>

      <p>这种方式每次发起请求的时候都需要将Session数据放到Cookie中传递给服务端。优点：不需要依赖额外外部存储，不需要额外配置。缺点：不安全，易被盗取或篡改；Cookie数量和长度有限制，需要消耗更多网络带宽。适用场景：数据不重要、不敏感且数据量小的情况。</p>
    </li>
    <li>
      <p>总结</p>

      <p>这四种方式，相对来说，Session集中管理更加可靠，使用也是最多的。</p>
    </li>
  </ol>

  <p>作者：JavaQ
链接：<a href="https://www.jianshu.com/p/3dd4e06bdfa4">https://www.jianshu.com/p/3dd4e06bdfa4</a>
來源：简书
著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。</p>
</blockquote>

<h4 id="jdbc-流程">JDBC 流程</h4>

<blockquote>
  <ol>
    <li>向DriverManager类注册驱动数据库驱动程序。</li>
    <li>调用DriverManager.getConnection方法， 通过JDBC URL，用户名，密码取得数据库连接的Connection对象。</li>
    <li>获取Connection后， 便可以通过createStatement创建Statement用以执行SQL语句。</li>
    <li>有时候会得到查询结果，比如select，得到查询结果，查询（SELECT）的结果存放于结果集（ResultSet）中。</li>
    <li>关闭数据库语句，关闭数据库连接。</li>
  </ol>
</blockquote>

<h4 id="mvc-设计思想">MVC 设计思想</h4>

<blockquote>
  <p>MVC是三个单词的首字母缩写，它们是Model（模型）、View（视图）和Controller（控制）。
这个模式认为，程序不论简单或复杂，从结构上看，都可以分成三层。</p>

  <ol>
    <li>最上面的一层，是直接面向最终用户的”视图层”（View）。它是提供给用户的操作界面，是程序的外壳。</li>
    <li>最底下的一层，是核心的”数据层”（Model），也就是程序需要操作的数据或信息。</li>
    <li>中间的一层，就是”控制层”（Controller），它负责根据用户从”视图层”输入的指令，选取”数据层”中的数据，然后对其进行相应的操作，产生最终结果。</li>
  </ol>
</blockquote>

<h4 id="equals-与--的区别">equals 与 == 的区别</h4>

<blockquote>
  <p>==与equals的主要区别是：</p>

  <ol>
    <li>==常用于比较原生类型，而equals()方法用于检查对象的相等性。</li>
    <li>如果==和equals()用于比较对象，当两个引用地址相同，==返回true。而equals()可以返回true或者false主要取决于重写实现。最常见的一个例子，字符串的比较，不同情况==和equals()返回不同的结果。</li>
    <li>使用==比较原生类型如：boolean、int、char等等，使用equals()比较对象。</li>
    <li>如果两个引用指向相同的对象，==返回true；equals()的返回结果依赖于具体业务实现。</li>
    <li>字符串的对比使用equals()代替==操作符。</li>
    <li>使用==比较原生类型如：boolean、int、char等等；使用equals()比较对象。</li>
  </ol>
</blockquote>

<h3 id="集合">集合</h3>

<h4 id="list-和-set-区别">List 和 Set 区别</h4>

<blockquote>
  <ol>
    <li>List,Set都是继承自Collection接口</li>
    <li>List特点：元素有放入顺序，元素可重复 ，Set特点：元素无放入顺序，元素不可重复（注意：元素虽然无放入顺序，但是元素在set中的位置是有该元素的HashCode决定的，其位置其实是固定的）</li>
    <li>List接口有三个实现类：LinkedList，ArrayList，Vector ，Set接口有两个实现类：HashSet(底层由HashMap实现)，LinkedHashSet</li>
  </ol>
</blockquote>

<h4 id="list-和-map-区别">List 和 Map 区别</h4>

<blockquote>
  <p>List特点：元素有放入顺序，元素可重复;
Map特点：元素按键值对存储，无放入顺序 ;
List接口有三个实现类：LinkedList，ArrayList，Vector;
LinkedList：底层基于链表实现，链表内存是散乱的，每一个元素存储本身内存地址的同时还存储下一个元素的地址。链表增删快，查找慢;
Map接口有三个实现类：HashMap，HashTable，LinkeHashMap
Map相当于和Collection一个级别的；Map该集合存储键值对，且要求保持键的唯一性；</p>
</blockquote>

<h4 id="arraylist-与-linkedlist-区别">Arraylist 与 LinkedList 区别</h4>

<blockquote>
  <ol>
    <li>因为Array是基于索引(index)的数据结构，它使用索引在数组中搜索和读取数据是很快的。Array获取数据的时间复杂度是O(1),但是要删除数据却是开销很大的，因为这需要重排数组中的所有数据。</li>
    <li>相对于ArrayList，LinkedList插入是更快的。因为LinkedList不像ArrayList一样，不需要改变数组的大小，也不需要在数组装满的时候要将所有的数据重新装入一个新的数组，这是ArrayList最坏的一种情况，时间复杂度是O(n)，而LinkedList中插入或删除的时间复杂度仅为O(1)。ArrayList在插入数据时还需要更新索引（除了插入数组的尾部）。</li>
    <li>类似于插入数据，删除数据时，LinkedList也优于ArrayList。</li>
    <li>LinkedList需要更多的内存，因为ArrayList的每个索引的位置是实际的数据，而LinkedList中的每个节点中存储的是实际的数据和前后节点的位置。</li>
    <li>你的应用不会随机访问数据。因为如果你需要LinkedList中的第n个元素的时候，你需要从第一个元素顺序数到第n个数据，然后读取数据。</li>
    <li>你的应用更多的插入和删除元素，更少的读取数据。因为插入和删除元素不涉及重排数据，所以它要比ArrayList要快。</li>
  </ol>
</blockquote>

<h4 id="arraylist-与-vector-区别">ArrayList 与 Vector 区别</h4>

<blockquote>
  <p>链接：<a href="https://www.nowcoder.com/questionTerminal/0953369f92054cbfbf1024a1e723e04f">https://www.nowcoder.com/questionTerminal/0953369f92054cbfbf1024a1e723e04f</a>
来源：牛客网</p>

  <ol>
    <li>同步性:Vector是线程安全的，也就是说是同步的 ，而ArrayList 是线程序不安全的，不是同步的 数2。</li>
    <li>数据增长:当需要增长时,Vector默认增长为原来一倍 ，而ArrayList却是原来的50% ，这样,ArrayList就有利于节约内存空间。</li>
  </ol>

  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>如果涉及到堆栈，队列等操作，应该考虑用Vector，如果需要快速随机访问元素，应该使用ArrayList 。
</code></pre></div>  </div>
</blockquote>

<h4 id="hashmap-和-hashtable-的区别">HashMap 和 Hashtable 的区别</h4>

<blockquote>
  <ol>
    <li>HashMap几乎可以等价于Hashtable，除了HashMap是非synchronized的，并可以接受null(HashMap可以接受为null的键值(key)和值(value)，而Hashtable则不行)。</li>
    <li>HashMap是非synchronized，而Hashtable是synchronized，这意味着Hashtable是线程安全的，多个线程可以共享一个Hashtable；而如果没有正确的同步的话，多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap，它是HashTable的替代，比HashTable的扩展性更好。</li>
    <li>另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器，而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构（增加或者移除元素），将会抛出ConcurrentModificationException，但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为，要看JVM。这条同样也是Enumeration和Iterator的区别。</li>
    <li>由于Hashtable是线程安全的也是synchronized，所以在单线程环境下它比HashMap要慢。如果你不需要同步，只需要单一线程，那么使用HashMap性能要好过Hashtable。</li>
    <li>HashMap不能保证随着时间的推移Map中的元素次序是不变的。</li>
  </ol>
</blockquote>

<h4 id="hashset-和-hashmap-区别">HashSet 和 HashMap 区别</h4>

<table>
  <thead>
    <tr>
      <th>HashMap</th>
      <th>HashSet</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>HashMap实现了Map接口</td>
      <td>HashSet实现了Set接口</td>
    </tr>
    <tr>
      <td>HashMap储存键值对</td>
      <td>HashSet仅仅存储对象</td>
    </tr>
    <tr>
      <td>使用put()方法将元素放入map中</td>
      <td>使用add()方法将元素放入set中</td>
    </tr>
    <tr>
      <td>HashMap中使用键对象来计算hashcode值</td>
      <td>HashSet使用成员对象来计算hashcode值，对于两个对象来说hashcode可能相同，所以equals()方法用来判断对象的相等性，如果两个对象不同的话，那么返回false</td>
    </tr>
    <tr>
      <td>HashMap比较快，因为是使用唯一的键来获取对象</td>
      <td>HashSet较HashMap来说比较慢</td>
    </tr>
  </tbody>
</table>

<h4 id="hashmap-和-concurrenthashmap-的区别">HashMap 和 ConcurrentHashMap 的区别</h4>

<blockquote>
  <ol>
    <li>放入HashMap的元素是key-value对。</li>
    <li>底层说白了就是以前数据结构课程讲过的散列结构。</li>
    <li>要将元素放入到hashmap中，那么key的类型必须要实现实现hashcode方法，默认这个方法是根据对象的地址来计算的，具体我也记不太清楚了，接着还必须覆盖对象的equal方法。</li>
    <li>ConcurrentHashMap对整个桶数组进行了分段，而HashMap则没有</li>
    <li>ConcurrentHashMap在每一个分段上都用锁进行保护，从而让锁的粒度更精细一些，并发性能更好，而HashMap没有锁机制，不是线程安全的。</li>
  </ol>
</blockquote>

<h4 id="hashmap-的工作原理及代码实现">HashMap 的工作原理及代码实现</h4>

<blockquote>
  <p>HashMap基于hashing原理，我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时，它调用键对象的hashCode()方法来计算hashcode，让后找到bucket位置来储存值对象。当获取对象时，通过键对象的equals()方法找到正确的键值对，然后返回值对象。HashMap使用链表来解决碰撞问题，当发生碰撞了，对象将会储存在链表的下一个节点中。 HashMap在每个链表节点中储存键值对对象。</p>
</blockquote>

<h4 id="concurrenthashmap-的工作原理及代码实现">ConcurrentHashMap 的工作原理及代码实现</h4>

<blockquote>
  <p>ConcurrentHashMap采用了非常精妙的”分段锁”策略，ConcurrentHashMap的主干是个Segment数组。Segment继承了ReentrantLock，所以它就是一种可重入锁（ReentrantLock)。在ConcurrentHashMap，一个Segment就是一个子哈希表，Segment里维护了一个HashEntry数组，并发环境下，对于不同Segment的数据进行操作是不用考虑锁竞争的。</p>
</blockquote>

<h3 id="线程">线程</h3>

<h4 id="创建线程的方式及实现">创建线程的方式及实现</h4>

<blockquote>
  <ol>
    <li>继承Thread类创建线程类
      <ol>
        <li>定义Thread类的子类，并重写该类的run方法，该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。</li>
        <li>创建Thread子类的实例，即创建了线程对象。</li>
        <li>调用线程对象的start()方法来启动该线程。</li>
      </ol>
    </li>
    <li>通过Runnable接口创建线程类
      <ol>
        <li>定义runnable接口的实现类，并重写该接口的run()方法，该run()方法的方法体同样是该线程的线程执行体。</li>
        <li>创建 Runnable实现类的实例，并依此实例作为Thread的target来创建Thread对象，该Thread对象才是真正的线程对象。</li>
        <li>调用线程对象的start()方法来启动该线程。</li>
      </ol>
    </li>
    <li>通过Callable和Future创建线程
      <ol>
        <li>创建Callable接口的实现类，并实现call()方法，该call()方法将作为线程执行体，并且有返回值。</li>
        <li>创建Callable实现类的实例，使用FutureTask类来包装Callable对象，该FutureTask对象封装了该Callable对象的call()方法的返回值。</li>
        <li>使用FutureTask对象作为Thread对象的target创建并启动新线程。</li>
        <li>调用FutureTask对象的get()方法来获得子线程执行结束后的返回值</li>
      </ol>
    </li>
  </ol>

  <p>采用实现Runnable、Callable接口的方式创见多线程时，优势是：</p>

  <ol>
    <li>线程类只是实现了Runnable接口或Callable接口，还可以继承其他类。</li>
    <li>多个线程可以共享同一个target对象，所以非常适合多个相同线程来处理同一份资源的情况，从而可以将CPU、代码和数据分开，形成清晰的模型，较好地体现了面向对象的思想。</li>
  </ol>

  <p>劣势是：</p>

  <ol>
    <li>编程稍微复杂，如果要访问当前线程，则必须使用Thread.currentThread()方法。</li>
  </ol>

  <p>使用继承Thread类的方式创建多线程时优势是：</p>

  <ol>
    <li>编写简单，如果需要访问当前线程，则无需使用Thread.currentThread()方法，直接使用this即可获得当前线程。</li>
  </ol>

  <p>劣势是：</p>

  <ol>
    <li>线程类已经继承了Thread类，所以不能再继承其他父类。</li>
  </ol>
</blockquote>

<h4 id="sleep-waitjoinyield-有什么区别">sleep() 、wait()、join()、yield() 有什么区别</h4>

<blockquote>
  <ul>
    <li>
      <p>sleep()</p>

      <p>sleep()方法需要指定等待的时间，它可以让当前正在执行的线程在指定的时间内暂停执行，进入阻塞状态，该方法既可以让其他同优先级或者高优先级的线程得到执行的机会，也可以让低优先级的线程得到执行机会。但是sleep()方法不会释放“锁标志”，也就是说如果有synchronized同步块，其他线程仍然不能访问共享数据。</p>
    </li>
  </ul>
</blockquote>

<blockquote>
  <ul>
    <li>
      <p>wait()</p>

      <p>wait()方法需要和notify()及notifyAll()两个方法一起介绍，这三个方法用于协调多个线程对共享数据的存取，所以必须在synchronized语句块内使用，也就是说，调用wait()，notify()和notifyAll()的任务在调用这些方法前必须拥有对象的锁。注意，它们都是Object类的方法，而不是Thread类的方法。</p>

      <p>wait()方法与sleep()方法的不同之处在于，wait()方法会释放对象的“锁标志”。当调用某一对象的wait()方法后，会使当前线程暂停执行，并将当前线程放入对象等待池中，直到调用了notify()方法后，将从对象等待池中移出任意一个线程并放入锁标志等待池中，只有锁标志等待池中的线程可以获取锁标志，它们随时准备争夺锁的拥有权。当调用了某个对象的notifyAll()方法，会将对象等待池中的所有线程都移动到该对象的锁标志等待池。</p>

      <p>除了使用notify()和notifyAll()方法，还可以使用带毫秒参数的wait(long timeout)方法，效果是在延迟timeout毫秒后，被暂停的线程将被恢复到锁标志等待池。</p>

      <p>此外，wait()，notify()及notifyAll()只能在synchronized语句中使用，但是如果使用的是ReenTrantLock实现同步，该如何达到这三个方法的效果呢？解决方法是使用ReenTrantLock.newCondition()获取一个Condition类对象，然后Condition的await()，signal()以及signalAll()分别对应上面的三个方法。</p>
    </li>
    <li>
      <p>yield()</p>

      <p>yield()方法和sleep()方法类似，也不会释放“锁标志”，区别在于，它没有参数，即yield()方法只是使当前线程重新回到可执行状态，所以执行yield()的线程有可能在进入到可执行状态后马上又被执行，另外yield()方法只能使同优先级或者高优先级的线程得到执行机会，这也和sleep()方法不同。</p>
    </li>
    <li>
      <p>join()</p>
    </li>
  </ul>

  <p>　　join()方法会使当前线程等待调用join()方法的线程结束后才能继续执行</p>
</blockquote>

<h4 id="说说-countdownlatch-原理">说说 CountDownLatch 原理</h4>

<blockquote>
  <p>CountDownLatch 内部维护了一个整数n，n（要大于等于0）在==当前线程== 初始化CountDownLatch方法指定。当前线程调用 CountDownLatch的await()方法阻塞当前线程，等待其他调用CountDownLatch对象的CountDown()方法的线程执行完毕。 其他线程调用该CountDownLatch的CountDown()方法，该方法会把n-1，直到所有线程执行完成，n等于0，==当前线程==就恢复执行。</p>
</blockquote>

<h4 id="说说-cyclicbarrier-原理">说说 CyclicBarrier 原理</h4>

<blockquote>
  <p>CyclicBarrier简介CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点(commonbarrierpoint)。因为该barrier在释放等待线程后可以重用,所以称它为循环的barrier。</p>
</blockquote>

<h4 id="说说-semaphore-原理">说说 Semaphore 原理</h4>

<blockquote>
  <p>Semaphore直译为信号。实际上Semaphore可以看做是一个信号的集合。不同的线程能够从Semaphore中获取若干个信号量。当Semaphore对象持有的信号量不足时，尝试从Semaphore中获取信号的线程将会阻塞。直到其他线程将信号量释放以后，阻塞的线程会被唤醒，重新尝试获取信号量。</p>
</blockquote>

<h4 id="说说-exchanger-原理">说说 Exchanger 原理</h4>

<blockquote>
  <p>当一个线程到达exchange调用点时，如果它的伙伴线程此前已经调用了此方法，那么它的伙伴会被调度唤醒并与之进行对象交换，然后各自返回。如果它的伙伴还没到达交换点，那么当前线程将会被挂起，直至伙伴线程到达——完成交换正常返回；或者当前线程被中断——抛出中断异常；又或者是等候超时——抛出超时异常。</p>
</blockquote>

<h4 id="说说-countdownlatch-与-cyclicbarrier-区别">说说 CountDownLatch 与 CyclicBarrier 区别</h4>

<blockquote>
  <ol>
    <li>CountDownLatch的作用是允许1或N个线程等待其他线程完成执行;而CyclicBarrier则是允许N个线程相互等待。</li>
    <li>CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置后使用,因此它被称为是循环的barrier。</li>
  </ol>
</blockquote>

<h4 id="threadlocal-原理分析">ThreadLocal 原理分析</h4>

<blockquote>
  <p>ThreadLocal提供了线程本地变量，它可以保证访问到的变量属于当前线程，每个线程都保存有一个变量副本，每个线程的变量都不同。ThreadLocal相当于提供了一种线程隔离，将变量与线程相绑定。</p>
</blockquote>

<h4 id="讲讲线程池的实现原理">讲讲线程池的实现原理</h4>

<blockquote>
  <p>当提交一个新任务到线程池时，线程池的处理流程如下。</p>

  <ol>
    <li>线程池判断核心线程池里的线程是否都在执行任务。如果不是，则创建一个新的工作线程来执行任务。如果核心线程池里的线程都在执行任务，则进入下个流程。</li>
    <li>线程池判断工作队列是否已经满。如果工作队列没有满，则将新提交的任务存储在这个工作队列里。如果工作队列满了，则进入下个流程。</li>
    <li>线程池判断线程池的线程是否都处于工作状态。如果没有，则创建一个新的工作线程来执行任务。如果已经满了，则交给饱和策略来处理这个任务。</li>
  </ol>
</blockquote>

<h4 id="线程池的几种方式">线程池的几种方式</h4>

<blockquote>
  <p>在Executors类里面提供了一些静态工厂，生成一些常用的线程池。</p>

  <ol>
    <li>newFixedThreadPool：创建固定大小的线程池。线程池的大小一旦达到最大值就会保持不变，如果某个线程因为执行异常而结束，那么线程池会补充一个新线程。</li>
    <li>newCachedThreadPool：创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程，那么就会回收部分空闲（60秒不执行任务）的线程，当任务数增加时，此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制，线程池大小完全依赖于操作系统（或者说JVM）能够创建的最大线程大小。</li>
    <li>newSingleThreadExecutor：创建一个单线程的线程池。这个线程池只有一个线程在工作，也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束，那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。</li>
    <li>newScheduledThreadPool：创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。</li>
    <li>newSingleThreadScheduledExecutor：创建一个单线程的线程池。此线程池支持定时以及周期性执行任务的需求。</li>
  </ol>
</blockquote>

<h4 id="线程的生命周期">线程的生命周期</h4>

<blockquote>
  <p>新建(New)、就绪（Runnable）、运行（Running）、阻塞(Blocked)和死亡(Dead)5种状态</p>
</blockquote>

<h3 id="锁机制">锁机制</h3>

<h4 id="说说线程安全问题">说说线程安全问题</h4>

<blockquote>
  <p>线程安全是多线程领域的问题，线程安全可以简单理解为一个方法或者一个实例可以在多线程环境中使用而不会出现问题。
在Java多线程编程当中，提供了多种实现Java线程安全的方式：</p>

  <ul>
    <li>最简单的方式，使用Synchronization关键字:Java Synchronization介绍</li>
    <li>使用java.util.concurrent.atomic 包中的原子类，例如 AtomicInteger</li>
    <li>使用java.util.concurrent.locks 包中的锁</li>
    <li>使用线程安全的集合ConcurrentHashMap</li>
    <li>使用volatile关键字，保证变量可见性（直接从内存读，而不是从线程cache读）</li>
  </ul>
</blockquote>

<h4 id="volatile-实现原理">volatile 实现原理</h4>

<blockquote>
  <ul>
    <li>在JVM底层volatile是采用“内存屏障”来实现的。</li>
    <li>缓存一致性协议（MESI协议）它确保每个缓存中使用的共享变量的副本是一致的。其核心思想如下：当某个CPU在写数据时，如果发现操作的变量是共享变量，则会通知其他CPU告知该变量的缓存行是无效的，因此其他CPU在读取该变量时，发现其无效会重新从主存中加载数据。</li>
  </ul>
</blockquote>

<h4 id="synchronize-实现原理">synchronize 实现原理</h4>

<blockquote>
  <p>同步代码块是使用monitorenter和monitorexit指令实现的，同步方法（在这看不出来需要看JVM底层实现）依靠的是方法修饰符上的ACC_SYNCHRONIZED实现。</p>
</blockquote>

<h4 id="synchronized-与-lock-的区别">synchronized 与 lock 的区别</h4>

<blockquote>
  <ol>
    <li>synchronized和lock的用法区别
      <ul>
        <li>synchronized(隐式锁)：在需要同步的对象中加入此控制，synchronized可以加在方法上，也可以加在特定代码块中，括号中表示需要锁的对象。</li>
        <li>lock（显示锁）：需要显示指定起始位置和终止位置。一般使用ReentrantLock类做为锁，多个线程中必须要使用一个ReentrantLock类做为对 象才能保证锁的生效。且在加锁和解锁处需要通过lock()和unlock()显示指出。所以一般会在finally块中写unlock()以防死锁。</li>
      </ul>
    </li>
    <li>synchronized和lock性能区别
      <ul>
        <li>synchronized是托管给JVM执行的，而lock是java写的控制锁的代码。</li>
        <li>在Java1.5中，synchronize是性能低效的。因为 这是一个重量级操作，需要调用操作接口，导致有可能加锁消耗的系统时间比加锁以外的操作还多。相比之下使用Java提供的Lock对象，性能更高一些。但 是到了Java1.6，发生了变化。synchronize在语义上很清晰，可以进行很多优化，有适应自旋，锁消除，锁粗化，轻量级锁，偏向锁等等。导致 在Java1.6上synchronize的性能并不比Lock差。</li>
      </ul>
    </li>
    <li>synchronized和lock机制区别
      <ul>
        <li>synchronized原始采用的是CPU悲观锁机制，即线程获得的是独占锁。独占锁意味着其 他线程只能依靠阻塞来等待线程释放锁。</li>
        <li>Lock用的是乐观锁方式。所谓乐观锁就是，每次不加锁而是假设没有冲突而去完成某项操作，如果因为冲突失败就重试，直到成功为止。乐观锁实现的机制就 是CAS操作（Compare and Swap）。</li>
      </ul>
    </li>
  </ol>
</blockquote>

<h4 id="cas-乐观锁">CAS 乐观锁</h4>

<blockquote>
  <p>CAS是项乐观锁技术，当多个线程尝试使用CAS同时更新同一个变量时，只有其中一个线程能更新变量的值，而其它线程都失败，失败的线程并不会被挂起，而是被告知这次竞争中失败，并可以再次尝试。
CAS 操作包含三个操作数 —— 内存位置（V）、预期原值（A）和新值(B)。如果内存位置的值与预期原值相匹配，那么处理器会自动将该位置值更新为新值。否则，处理器不做任何操作。无论哪种情况，它都会在 CAS 指令之前返回该位置的值。（在 CAS 的一些特殊情况下将仅返回 CAS 是否成功，而不提取当前值。）CAS 有效地说明了“我认为位置 V 应该包含值 A；如果包含该值，则将 B 放到这个位置；否则，不要更改该位置，只告诉我这个位置现在的值即可。”这其实和乐观锁的冲突检查+数据更新的原理是一样的。</p>
</blockquote>

<h4 id="aba-问题">ABA 问题</h4>

<blockquote>
  <p>CAS会导致“ABA问题”。
CAS算法实现一个重要前提需要取出内存中某时刻的数据，而在下时刻比较并替换，那么在这个时间差类会导致数据的变化。
比如说一个线程one从内存位置V中取出A，这时候另一个线程two也从内存中取出A，并且two进行了一些操作变成了B，然后two又将V位置的数据变成A，这时候线程one进行CAS操作发现内存中仍然是A，然后one操作成功。尽管线程one的CAS操作成功，但是不代表这个过程就是没有问题的。
部分乐观锁的实现是通过版本号（version）的方式来解决ABA问题，乐观锁每次在执行数据的修改操作时，都会带上一个版本号，一旦版本号和数据的版本号一致就可以执行修改操作并对版本号执行+1操作，否则就执行失败。因为每次操作的版本号都会随之增加，所以不会出现ABA问题，因为版本号只会增加不会减少。</p>
</blockquote>

<h4 id="乐观锁的业务场景及实现方式">乐观锁的业务场景及实现方式</h4>

<blockquote>
  <p>乐观锁（Optimistic Lock）：
每次获取数据的时候，都不会担心数据被修改，所以每次获取数据的时候都不会进行加锁，但是在更新数据的时候需要判断该数据是否被别人修改过。如果数据被其他线程修改，则不进行数据更新，如果数据没有被其他线程修改，则进行数据更新。由于数据没有进行加锁，期间该数据可以被其他线程进行读写操作。
比较适合读取操作比较频繁的场景，如果出现大量的写入操作，数据发生冲突的可能性就会增大，为了保证数据的一致性，应用层需要不断的重新获取数据，这样会增加大量的查询操作，降低了系统的吞吐量。</p>
</blockquote>

<h2 id="转载来源">转载来源</h2>

<p><a href="https://my.oschina.net/xiaomingnevermind/blog/1787269">Java面试通关要点汇总集基础篇之参考答案</a></p>]]></content><author><name>Kuradeon</name></author><category term="Java" /><category term="面试" /><category term="集合" /><category term="线程" /><category term="锁" /><summary type="html"><![CDATA[基础篇 基本功 面向对象的特征 面向对象的三个基本特征是：封装、继承、多态。 封装 封装最好理解了。封装是面向对象的特征之一，是对象和类概念的主要特性。 封装，也就是把客观事物封装成抽象的类，并且类可以把自己的数据和方法只让可信的类或者对象操作，对不可信的进行信息隐藏。 继承 面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力：它可以使用现有类的所有功能，并在无需重新编写原来的类的情况下对这些功能进行扩展。 多态 多态性（polymorphisn）是允许你将父对象设置成为和一个或更多的他的子对象相等的技术，赋值之后，父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说，就是一句话：允许将子类类型的指针赋值给父类类型的指针。 实现多态，有二种方式，覆盖，重载。]]></summary></entry><entry><title type="html">Spring 事务传播行为</title><link href="https://www.kuradeon.cn/2018/02/27/Spring-%E4%BA%8B%E5%8A%A1%E4%BC%A0%E6%92%AD%E8%A1%8C%E4%B8%BA.html" rel="alternate" type="text/html" title="Spring 事务传播行为" /><published>2018-02-27T00:00:00+00:00</published><updated>2018-02-27T00:00:00+00:00</updated><id>https://www.kuradeon.cn/2018/02/27/Spring%20%E4%BA%8B%E5%8A%A1%E4%BC%A0%E6%92%AD%E8%A1%8C%E4%B8%BA</id><content type="html" xml:base="https://www.kuradeon.cn/2018/02/27/Spring-%E4%BA%8B%E5%8A%A1%E4%BC%A0%E6%92%AD%E8%A1%8C%E4%B8%BA.html"><![CDATA[<h2 id="spring事务传播属性">Spring事务传播属性</h2>

<p>Spring 事务传播属性，描述了Spring 的各个事务方法在相互调用时，事务是如何进行传播的。<!--more--></p>

<p>Spring 事务有七个传播属性</p>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180227/C2fDbK04kD.jpeg" alt="C2fDbK04kD" /></p>

<h2 id="spring-事务控制原理">Spring 事务控制原理</h2>

<p><strong>Spring 的事务控制是通过 Spring AOP 实现</strong>的，事务的 commit 或 rollback 操作都在 Spring 创建的代理类中实现。</p>

<p>举例说明，ServiceA.method1() 方法配置了 Spring 事务，实际 Spring 通过 AOP 生成了类 $ProxyA ，通过调用 $ProxyA 中增强的 method1() 方法（加入事务控制）来实现业务功能 &amp; 事务控制。</p>

<h2 id="spring-事务传播的误区">Spring 事务传播的误区</h2>

<p>有的同学可能会遇到一个问题，method1() 中调用 method2()，明明调用的 method2() 已经配置事务传播属性为 required_new，可是 Spring 并未给 method2() 开启新的事务。</p>

<p>查看代码发现，原来 method1() 和 method2() 在同一个类 ServiceA 中。</p>

<p>通过 Spring 事务控制原理可知，Spring 会生成代理类 $ServiceA，并通过调用 $ServiceA.method1() 来实现业务功能及事务控制；此时在 $ServiceA.method1() 中调用 method2()，实际上是不会生成新的代理类来增强 method2() 的，所以这时候 Spring 不会给 method2() 开启新的事务。</p>

<p>因此可知，<strong>同一个类中的方法相互调用，事务传播行为由最外层的方法的事务传播属性决定</strong>。</p>

<p>要解决这个问题，我目前知道有如下3种方法：</p>

<ul>
  <li>
    <p>新建类 ServiceB，将 method2() 迁移到新的类中；</p>
  </li>
  <li>
    <p>在 ServiceA.method1() 中，重新通过 Spring IOC 获取 ServiceA</p>

    <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">ServiceA</span> <span class="n">serviceA2</span> <span class="o">=</span> <span class="n">applicationContext</span><span class="o">.</span><span class="na">getBean</span><span class="o">(</span><span class="s">"serviceA"</span><span class="o">);</span>
</code></pre></div>    </div>

    <p>再通过新获取的 serviceA2 来调用 method2()。此方法不推荐。</p>
  </li>
  <li>
    <p>通过Spring配置暴露代理</p>

    <ul>
      <li>
        <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;aop:aspectj-autoproxy</span> <span class="na">expose-proxy=</span><span class="s">"true"</span><span class="nt">/&gt;</span>
</code></pre></div>        </div>
        <p>或</p>
      </li>
      <li>
        <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;aop:config</span> <span class="na">expose-proxy=</span><span class="s">"true"</span><span class="nt">/&gt;</span>
</code></pre></div>        </div>
        <p>总而言之，尽量通过合理的建模或设计来利用Spring AOP带来的方便，并避免随之带来的问题。</p>
      </li>
    </ul>
  </li>
</ul>]]></content><author><name>Kuradeon</name></author><category term="Spring" /><category term="事务传播" /><summary type="html"><![CDATA[Spring事务传播属性 Spring 事务传播属性，描述了Spring 的各个事务方法在相互调用时，事务是如何进行传播的。]]></summary></entry><entry><title type="html">Windows环境安装Ruby+RubyGem+DevKit+Jekyll</title><link href="https://www.kuradeon.cn/2018/02/06/Windows%E7%8E%AF%E5%A2%83%E5%AE%89%E8%A3%85Ruby+RubyGem+DevKit+Jekyll.html" rel="alternate" type="text/html" title="Windows环境安装Ruby+RubyGem+DevKit+Jekyll" /><published>2018-02-06T00:00:00+00:00</published><updated>2018-02-06T00:00:00+00:00</updated><id>https://www.kuradeon.cn/2018/02/06/Windows%E7%8E%AF%E5%A2%83%E5%AE%89%E8%A3%85Ruby+RubyGem+DevKit+Jekyll</id><content type="html" xml:base="https://www.kuradeon.cn/2018/02/06/Windows%E7%8E%AF%E5%A2%83%E5%AE%89%E8%A3%85Ruby+RubyGem+DevKit+Jekyll.html"><![CDATA[<h2 id="1安装ruby">1.安装Ruby</h2>

<ol>
  <li>下载Rubyinstall安装包https://rubyinstaller.org/downloads/，选择对应版本安装<!--more--></li>
</ol>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180206/eDaHbhG9kb.png" alt="eDaHbhG9kb" /></p>

<ol>
  <li>
    <p>配置环境变量</p>

    <ol>
      <li>添加环境变量：RUBY_HOME</li>
    </ol>

    <p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180206/A4hC4K69m1.png" alt="A4hC4K69m1" /></p>

    <ol>
      <li>
        <p>修改path环境变量，添加地址：</p>

        <p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180206/1eDeF43cI0.png" alt="1eDeF43cI0" /></p>
      </li>
      <li>
        <p>测试ruby是否安装成功</p>

        <p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180206/Kgc767922C.png" alt="Kgc767922C" /></p>
      </li>
    </ol>
  </li>
</ol>

<h2 id="2安装rubygem">2.安装RubyGem</h2>

<p>一般情况下，安装完RubyInstall后，gem已经安装完毕。</p>

<p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180206/G5J6B9chBb.png" alt="G5J6B9chBb" /></p>

<p>如果安装失败，可以下载rubygem自行安装https://rubygems.org/pages/download</p>

<p>Or, to upgrade to the latest RubyGems:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ gem update --system          # may need to be administrator or root
</code></pre></div></div>

<p><strong>NOTE:</strong> RubyGems 1.1 and 1.2 have problems upgrading when there is no rubygems-update installed. You will need to use the following instructions if you see <code class="language-plaintext highlighter-rouge">Nothing to update</code>. If you have an older version of RubyGems installed, then you can still do it in two steps:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ gem install rubygems-update  # again, might need to be admin/root
$ update_rubygems              # ... here too
</code></pre></div></div>

<p>If you don’t have any RubyGems installed, there is still the pre-gem approach to getting software, doing it manually:</p>

<ol>
  <li><a href="https://rubygems.org/pages/download#formats">Download from above</a></li>
  <li>Unpack into a directory and <code class="language-plaintext highlighter-rouge">cd</code> there</li>
  <li>Install with: <code class="language-plaintext highlighter-rouge">ruby setup.rb</code> (you may need admin/root privilege)</li>
</ol>

<p>For more details and other options, see:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ruby setup.rb <span class="nt">--help</span>
</code></pre></div></div>

<h2 id="3安装devkit">3.安装DevKit</h2>

<ol>
  <li>
    <p>于Ruby网站下载Devkit</p>

    <p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180206/DdC0hhHE9E.png" alt="DdC0hhHE9E" /></p>
  </li>
  <li>
    <p>运行解压后，安装DevKit：</p>

    <div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">D:\DevKit</span><span class="err">&gt;</span><span class="nx">ruby</span><span class="w"> </span><span class="nx">dk.rb</span><span class="w"> </span><span class="nx">init</span><span class="w">
</span><span class="p">[</span><span class="n">INFO</span><span class="p">]</span><span class="w"> </span><span class="n">found</span><span class="w"> </span><span class="nx">RubyInstaller</span><span class="w"> </span><span class="nx">v2.5.0</span><span class="w"> </span><span class="nx">at</span><span class="w"> </span><span class="nx">D:/Ruby25-x64</span><span class="w">

</span><span class="n">Initialization</span><span class="w"> </span><span class="nx">complete</span><span class="o">!</span><span class="w"> </span><span class="nx">Please</span><span class="w"> </span><span class="nx">review</span><span class="w"> </span><span class="nx">and</span><span class="w"> </span><span class="nx">modify</span><span class="w"> </span><span class="nx">the</span><span class="w"> </span><span class="nx">auto-generated</span><span class="w">
</span><span class="s1">'config.yml'</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="nx">to</span><span class="w"> </span><span class="nx">ensure</span><span class="w"> </span><span class="nx">it</span><span class="w"> </span><span class="nx">contains</span><span class="w"> </span><span class="nx">the</span><span class="w"> </span><span class="nx">root</span><span class="w"> </span><span class="nx">directories</span><span class="w"> </span><span class="nx">to</span><span class="w"> </span><span class="nx">all</span><span class="w">
</span><span class="n">of</span><span class="w"> </span><span class="nx">the</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">Rubies</span><span class="w"> </span><span class="nx">you</span><span class="w"> </span><span class="nx">want</span><span class="w"> </span><span class="nx">enhanced</span><span class="w"> </span><span class="nx">by</span><span class="w"> </span><span class="nx">the</span><span class="w"> </span><span class="nx">DevKit.</span><span class="w">
</span></code></pre></div>    </div>

    <p>根据提示可能需要修改config.yml里面ruby的根目录</p>

    <p>修改完毕后可以回顾安装信息</p>

    <div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">D:\DevKit</span><span class="err">&gt;</span><span class="nx">ruby</span><span class="w"> </span><span class="nx">dk.rb</span><span class="w"> </span><span class="nx">review</span><span class="w">
</span><span class="n">Based</span><span class="w"> </span><span class="nx">upon</span><span class="w"> </span><span class="nx">the</span><span class="w"> </span><span class="nx">settings</span><span class="w"> </span><span class="nx">in</span><span class="w"> </span><span class="nx">the</span><span class="w"> </span><span class="s1">'config.yml'</span><span class="w"> </span><span class="nx">file</span><span class="w"> </span><span class="nx">generated</span><span class="w">
</span><span class="kr">from</span><span class="w"> </span><span class="n">running</span><span class="w"> </span><span class="s1">'ruby dk.rb init'</span><span class="w"> </span><span class="nx">and</span><span class="w"> </span><span class="nx">any</span><span class="w"> </span><span class="nx">of</span><span class="w"> </span><span class="nx">your</span><span class="w"> </span><span class="nx">customizations</span><span class="p">,</span><span class="w">
</span><span class="n">DevKit</span><span class="w"> </span><span class="nx">functionality</span><span class="w"> </span><span class="nx">will</span><span class="w"> </span><span class="nx">be</span><span class="w"> </span><span class="nx">injected</span><span class="w"> </span><span class="nx">into</span><span class="w"> </span><span class="nx">the</span><span class="w"> </span><span class="nx">following</span><span class="w"> </span><span class="nx">Rubies</span><span class="w">
</span><span class="n">when</span><span class="w"> </span><span class="nx">you</span><span class="w"> </span><span class="nx">run</span><span class="w"> </span><span class="s1">'ruby dk.rb install'</span><span class="o">.</span><span class="w">
</span></code></pre></div>    </div>

    <p>最后安装DevKit</p>

    <div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">D:\DevKit</span><span class="err">&gt;</span><span class="nx">ruby</span><span class="w"> </span><span class="nx">dk.rb</span><span class="w"> </span><span class="nx">install</span><span class="w">
</span><span class="p">[</span><span class="n">INFO</span><span class="p">]</span><span class="w"> </span><span class="n">Skipping</span><span class="w"> </span><span class="nx">existing</span><span class="w"> </span><span class="nx">gem</span><span class="w"> </span><span class="nx">override</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="s1">'D:/Ruby25-x64'</span><span class="w">
</span><span class="p">[</span><span class="n">WARN</span><span class="p">]</span><span class="w"> </span><span class="n">Skipping</span><span class="w"> </span><span class="nx">existing</span><span class="w"> </span><span class="nx">DevKit</span><span class="w"> </span><span class="nx">helper</span><span class="w"> </span><span class="nx">library</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="s1">'D:/Ruby25-x64'</span><span class="w">
</span></code></pre></div>    </div>
  </li>
  <li>
    <p>配置DevKit环境变量</p>

    <ol>
      <li>配置DEVKIT_HOME</li>
    </ol>

    <p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180206/aKL3dFeCEB.png" alt="aKL3dFeCEB" /></p>

    <ol>
      <li>
        <p>添加Path路径</p>

        <p><img src="https://raw.githubusercontent.com/ImagineBrain/imaginebrain.github.io/master/_posts/img/180206/0hJH7ei0FG.png" alt="0hJH7ei0FG" /></p>
      </li>
    </ol>
  </li>
</ol>

<h2 id="4安装jekyll">4.安装Jekyll</h2>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">D:\DevKit</span><span class="err">&gt;</span><span class="nx">gem</span><span class="w"> </span><span class="nx">install</span><span class="w"> </span><span class="nx">jekyll</span><span class="w">
</span><span class="n">Temporarily</span><span class="w"> </span><span class="nx">enhancing</span><span class="w"> </span><span class="nx">PATH</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">MSYS/MINGW...</span><span class="w">
</span><span class="n">Building</span><span class="w"> </span><span class="nx">native</span><span class="w"> </span><span class="nx">extensions.</span><span class="w"> </span><span class="nx">This</span><span class="w"> </span><span class="nx">could</span><span class="w"> </span><span class="nx">take</span><span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="nx">while...</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">http_parser.rb-0.6.0</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">eventmachine-1.2.5-x64-mingw32.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">eventmachine-1.2.5-x64-mingw32</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">em-websocket-0.5.1.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">em-websocket-0.5.1</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">concurrent-ruby-1.0.5.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">concurrent-ruby-1.0.5</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">i18n-0.9.3.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">i18n-0.9.3</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">rb-fsevent-0.10.2.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">rb-fsevent-0.10.2</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">ffi-1.9.18-x64-mingw32.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">ERROR:</span><span class="w">  </span><span class="nx">Error</span><span class="w"> </span><span class="nx">installing</span><span class="w"> </span><span class="nx">jekyll:</span><span class="w">
</span></code></pre></div></div>
<p>安装Jekyll报错，发现不支持Ruby2.5，于是笔者便更换了Ruby 2.4.3来继续安装Jekyll</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">D:\DevKit</span><span class="err">&gt;</span><span class="nx">gem</span><span class="w"> </span><span class="nx">install</span><span class="w"> </span><span class="nx">jekyll</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">public_suffix-3.0.1.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">public_suffix-3.0.1</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">addressable-2.5.2.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">addressable-2.5.2</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">colorator-1.1.0.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">colorator-1.1.0</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">http_parser.rb-0.6.0.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Temporarily</span><span class="w"> </span><span class="nx">enhancing</span><span class="w"> </span><span class="nx">PATH</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">MSYS/MINGW...</span><span class="w">
</span><span class="n">Building</span><span class="w"> </span><span class="nx">native</span><span class="w"> </span><span class="nx">extensions.</span><span class="w">  </span><span class="nx">This</span><span class="w"> </span><span class="nx">could</span><span class="w"> </span><span class="nx">take</span><span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="nx">while...</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">http_parser.rb-0.6.0</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">eventmachine-1.2.5-x64-mingw32.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">eventmachine-1.2.5-x64-mingw32</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">em-websocket-0.5.1.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">em-websocket-0.5.1</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">concurrent-ruby-1.0.5.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">concurrent-ruby-1.0.5</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">i18n-0.9.3.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">i18n-0.9.3</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">rb-fsevent-0.10.2.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">rb-fsevent-0.10.2</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">ffi-1.9.18-x64-mingw32.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">ffi-1.9.18-x64-mingw32</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">rb-inotify-0.9.10.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">rb-inotify-0.9.10</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">sass-listen-4.0.0.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">sass-listen-4.0.0</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">sass-3.5.5.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">sass-3.5.5</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">jekyll-sass-converter-1.5.2.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">jekyll-sass-converter-1.5.2</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">ruby_dep-1.5.0.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">ruby_dep-1.5.0</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">listen-3.1.5.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">listen-3.1.5</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">jekyll-watch-2.0.0.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">jekyll-watch-2.0.0</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">kramdown-1.16.2.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">kramdown-1.16.2</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">liquid-4.0.0.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">liquid-4.0.0</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">mercenary-0.3.6.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">mercenary-0.3.6</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">forwardable-extended-2.6.0.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">forwardable-extended-2.6.0</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">pathutil-0.16.1.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">pathutil-0.16.1</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">rouge-3.1.1.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">rouge-3.1.1</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">safe_yaml-1.0.4.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">safe_yaml-1.0.4</span><span class="w">
</span><span class="n">Fetching:</span><span class="w"> </span><span class="nx">jekyll-3.7.2.gem</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="o">%</span><span class="p">)</span><span class="w">
</span><span class="n">Successfully</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">jekyll-3.7.2</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">public_suffix-3.0.1</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">public_suffix-3.0.1</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">addressable-2.5.2</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">addressable-2.5.2</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">colorator-1.1.0</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">colorator-1.1.0</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">http_parser.rb-0.6.0</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">http_parser.rb-0.6.0</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">eventmachine-1.2.5-x64-mingw32</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">eventmachine-1.2.5-x64-mingw32</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">em-websocket-0.5.1</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">em-websocket-0.5.1</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">concurrent-ruby-1.0.5</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">concurrent-ruby-1.0.5</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">i18n-0.9.3</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">i18n-0.9.3</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">rb-fsevent-0.10.2</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">rb-fsevent-0.10.2</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">ffi-1.9.18-x64-mingw32</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">ffi-1.9.18-x64-mingw32</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">rb-inotify-0.9.10</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">rb-inotify-0.9.10</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">sass-listen-4.0.0</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">sass-listen-4.0.0</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">sass-3.5.5</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">sass-3.5.5</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">jekyll-sass-converter-1.5.2</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">jekyll-sass-converter-1.5.2</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">ruby_dep-1.5.0</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">ruby_dep-1.5.0</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">listen-3.1.5</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">listen-3.1.5</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">jekyll-watch-2.0.0</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">jekyll-watch-2.0.0</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">kramdown-1.16.2</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">kramdown-1.16.2</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">liquid-4.0.0</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">liquid-4.0.0</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">mercenary-0.3.6</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">mercenary-0.3.6</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">forwardable-extended-2.6.0</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">forwardable-extended-2.6.0</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">pathutil-0.16.1</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">pathutil-0.16.1</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">rouge-3.1.1</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">rouge-3.1.1</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">safe_yaml-1.0.4</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">safe_yaml-1.0.4</span><span class="w">
</span><span class="n">Parsing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">jekyll-3.7.2</span><span class="w">
</span><span class="n">Installing</span><span class="w"> </span><span class="nx">ri</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">jekyll-3.7.2</span><span class="w">
</span><span class="n">Done</span><span class="w"> </span><span class="nx">installing</span><span class="w"> </span><span class="nx">documentation</span><span class="w"> </span><span class="nx">for</span><span class="w"> </span><span class="nx">public_suffix</span><span class="p">,</span><span class="w"> </span><span class="nx">addressable</span><span class="p">,</span><span class="w"> </span><span class="nx">colorator</span><span class="p">,</span><span class="w"> </span><span class="nx">http_parser.rb</span><span class="p">,</span><span class="w"> </span><span class="nx">eventmachine</span><span class="p">,</span><span class="w"> </span><span class="nx">em-websocket</span><span class="p">,</span><span class="w"> </span><span class="nx">concurrent-ruby</span><span class="p">,</span><span class="w"> </span><span class="nx">i18n</span><span class="p">,</span><span class="w"> </span><span class="nx">rb-fsevent</span><span class="p">,</span><span class="w"> </span><span class="nx">ffi</span><span class="p">,</span><span class="w"> </span><span class="nx">rb-inotify</span><span class="p">,</span><span class="w"> </span><span class="nx">sass-listen</span><span class="p">,</span><span class="w"> </span><span class="nx">sass</span><span class="p">,</span><span class="w"> </span><span class="nx">jekyll-sass-converter</span><span class="p">,</span><span class="w"> </span><span class="nx">ruby_dep</span><span class="p">,</span><span class="w"> </span><span class="nx">listen</span><span class="p">,</span><span class="w"> </span><span class="nx">jekyll-watch</span><span class="p">,</span><span class="w"> </span><span class="nx">kramdown</span><span class="p">,</span><span class="w"> </span><span class="nx">liquid</span><span class="p">,</span><span class="w"> </span><span class="nx">mercenary</span><span class="p">,</span><span class="w"> </span><span class="nx">forwardable-extended</span><span class="p">,</span><span class="w"> </span><span class="nx">pathutil</span><span class="p">,</span><span class="w"> </span><span class="nx">rouge</span><span class="p">,</span><span class="w"> </span><span class="nx">safe_yaml</span><span class="p">,</span><span class="w"> </span><span class="nx">jekyll</span><span class="w"> </span><span class="nx">after</span><span class="w"> </span><span class="nx">40</span><span class="w"> </span><span class="nx">seconds</span><span class="w">
</span><span class="mi">25</span><span class="w"> </span><span class="n">gems</span><span class="w"> </span><span class="nx">installed</span><span class="w">
</span></code></pre></div></div>

<p>到此安装完毕</p>]]></content><author><name>Kuradeon</name></author><category term="Ruby+RubyGem+DevKit+Jekyll安装" /><summary type="html"><![CDATA[1.安装Ruby 下载Rubyinstall安装包https://rubyinstaller.org/downloads/，选择对应版本安装]]></summary></entry><entry><title type="html">单例模式双重检查中volatile作用</title><link href="https://www.kuradeon.cn/2018/02/05/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F%E5%8F%8C%E9%87%8D%E6%A3%80%E6%9F%A5%E4%B8%ADvolatile%E4%BD%9C%E7%94%A8.html" rel="alternate" type="text/html" title="单例模式双重检查中volatile作用" /><published>2018-02-05T00:00:00+00:00</published><updated>2018-02-05T00:00:00+00:00</updated><id>https://www.kuradeon.cn/2018/02/05/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F%E5%8F%8C%E9%87%8D%E6%A3%80%E6%9F%A5%E4%B8%ADvolatile%E4%BD%9C%E7%94%A8</id><content type="html" xml:base="https://www.kuradeon.cn/2018/02/05/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F%E5%8F%8C%E9%87%8D%E6%A3%80%E6%9F%A5%E4%B8%ADvolatile%E4%BD%9C%E7%94%A8.html"><![CDATA[<h1 id="1-volatile作用">1. volatile作用</h1>

<ol>
  <li>volatile可以保证变量和可见性，让修饰的变量直接从主存中获取值；</li>
  <li>volatile可以防止指令重排序</li>
</ol>

<!--more-->

<h1 id="2-volatile的误区">2. volatile的误区</h1>

<p>volatile无法保证复合操作的原子性。</p>

<h1 id="3-单例模式双重检查中volatile的作用">3. 单例模式双重检查中Volatile的作用</h1>

<p>在单例模式的饿汉式实现中，为了缩小锁的范围，使用双重检查。</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">DoubleCheckMode</span> <span class="o">{</span>
    <span class="cm">/**
     * volatile 保证可见性(双重检查用synchronized保证可见性)，防止指令重排序
     */</span>
    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">volatile</span> <span class="nc">DoubleCheckMode</span> <span class="n">instance</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>

    <span class="cm">/**
     * 构造函数私有化
     */</span>
    <span class="kd">private</span> <span class="nf">DoubleCheckMode</span><span class="o">()</span> <span class="o">{</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="nc">DoubleCheckMode</span> <span class="nf">getInstance</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">instance</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
            <span class="kd">synchronized</span> <span class="o">(</span><span class="nc">DoubleCheckMode</span><span class="o">.</span><span class="na">class</span><span class="o">)</span> <span class="o">{</span>
                <span class="cm">/**
                 * 双重检查，缩小锁的范围
                 */</span>
                <span class="k">if</span> <span class="o">(</span><span class="n">instance</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
                    <span class="cm">/**
                     * volatile防止如下重排序
                     * 指令执行顺序：
                     * 1.分配内存空间; 2.实例化对象; 3.将内存空间地址赋值给instance引用
                     * 可能被重排序为：
                     * 1.分配内存空间; 2.将内存空间地址赋值给instance引用; 3.实例化对象
                     * 使用volatile修饰，防止指令重排序
                     */</span>
                    <span class="n">instance</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">DoubleCheckMode</span><span class="o">();</span>
                <span class="o">}</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">instance</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>在</p>

<p>instance = new DoubleCheckMode();</p>

<p>这行代码中，包含如下3条指令：</p>

<ol>
  <li>分配内存空间；</li>
  <li>实例化对象；</li>
  <li>将内存地址赋值给instance引用</li>
</ol>

<p>可能被重排序为：</p>

<ol>
  <li>分配内存空间；</li>
  <li>将内存地址赋值给instance引用；</li>
  <li>实例化对象</li>
</ol>

<p>在多线程模型中，如果Thread A刚执行完重排序后的1、2条指令；线程Thread B进行双重检查判断时，instance将不为null，此时会获得不完整的实例化对象。此时使用volatile修饰instance，防止指令重排序，保证多线程模型下能正确获得实例对象。</p>]]></content><author><name>Kuradeon</name></author><category term="volatile" /><category term="单例模式" /><category term="双重检查" /><summary type="html"><![CDATA[1. volatile作用 volatile可以保证变量和可见性，让修饰的变量直接从主存中获取值； volatile可以防止指令重排序]]></summary></entry></feed>