Memcached学习笔记 — 第四部分:Memcached Java 客户端-gwhalin(1)-介绍及使用



介绍

Memcached java client是官方推荐的最早的memcached java客户端。最新版本:java_memcached-release_2.6.1。

官方下载地址:https://github.com/gwhalin/Memcached-Java-Client

采用阻塞式SOCKET通讯,据说目前版本进行了很多优化,性能有所提高(只看过1.5的源代码,还没来及看最新的)
提供key方式的连接池,默认连接池key为default。(老版本了)。2.6.1版本支持apache-commoms-pool作为连接池。
支持权重配置。
后期的版本提增加了cas支持和getMutl功能

官方示例代码

Java代码  

  1. import com.danga.MemCached.MemCachedClient;  
  2. import com.danga.MemCached.SockIOPool;  
  3. import com.schooner.MemCached.MemcachedItem;  
  4.   
  5. public class MemcachedForJavaExample {  
  6.   
  7.     // create a static client as most installs only need  
  8.     // a single instance  
  9.     protected static MemCachedClient mcc = new MemCachedClient();  
  10.   
  11.     // set up connection pool once at class load  
  12.     static {  
  13.   
  14.         // server list and weights  
  15.         String[] servers = { "localhost:11211", "localhost:11212", "localhost:11213" };  
  16.   
  17.         Integer[] weights = { 3, 3, 2 };  
  18.   
  19.         // grab an instance of our connection pool  
  20.         SockIOPool pool = SockIOPool.getInstance();  
  21.   
  22.         // set the servers and the weights  
  23.         pool.setServers(servers);  
  24.         pool.setWeights(weights);  
  25.         pool.setHashingAlg(SockIOPool.CONSISTENT_HASH);  
  26.   
  27.         // set some basic pool settings  
  28.         // 5 initial, 5 min, and 250 max conns  
  29.         // and set the max idle time for a conn  
  30.         // to 6 hours  
  31.         pool.setInitConn(5);  
  32.         pool.setMinConn(5);  
  33.         pool.setMaxConn(250);  
  34.         pool.setMaxIdle(1000 * 60 * 60 * 6);  
  35.   
  36.         // set the sleep for the maint thread  
  37.         // it will wake up every x seconds and  
  38.         // maintain the pool size  
  39.         pool.setMaintSleep(30);  
  40.   
  41.         // set some TCP settings  
  42.         // disable nagle  
  43.         // set the read timeout to 3 secs  
  44.         // and don't set a connect timeout  
  45.         pool.setNagle(false);  
  46.         pool.setSocketTO(3000);  
  47.         pool.setSocketConnectTO(0);  
  48.   
  49.         // initialize the connection pool  
  50.         pool.initialize();  
  51.     }  
  52.   
  53.     public static void main(String[] args) {  
  54.         System.out.println("SET: " + mcc.set("key1", "value1"));  
  55.         System.out.println("SET: " + mcc.set("key2", "value2"));  
  56.         System.out.println("SET: " + mcc.set("key3", "value3"));  
  57.         System.out.println("GET: " + mcc.get("key1"));  
  58.         MemcachedItem item = mcc.gets("key1");  
  59.         System.out.println("GETS: value=" + item.getValue() + ",CasUnique:"+item.getCasUnique());  
  60.         System.out.println("SET: " + mcc.set("key1", "value1_1"));  
  61.         System.out.println("CAS: " + mcc.cas("key1", "value1_2", item.getCasUnique())); //必须FALSE  
  62.         System.out.println("getMulti:" + mcc.getMulti(new String[]{"key1","key2","key3"}));  
  63.     }  
  64.   
  65. }  
import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;
import com.schooner.MemCached.MemcachedItem;

public class MemcachedForJavaExample {

	// create a static client as most installs only need
	// a single instance
	protected static MemCachedClient mcc = new MemCachedClient();

	// set up connection pool once at class load
	static {

		// server list and weights
		String[] servers = { "localhost:11211", "localhost:11212", "localhost:11213" };

		Integer[] weights = { 3, 3, 2 };

		// grab an instance of our connection pool
		SockIOPool pool = SockIOPool.getInstance();

		// set the servers and the weights
		pool.setServers(servers);
		pool.setWeights(weights);
		pool.setHashingAlg(SockIOPool.CONSISTENT_HASH);

		// set some basic pool settings
		// 5 initial, 5 min, and 250 max conns
		// and set the max idle time for a conn
		// to 6 hours
		pool.setInitConn(5);
		pool.setMinConn(5);
		pool.setMaxConn(250);
		pool.setMaxIdle(1000 * 60 * 60 * 6);

		// set the sleep for the maint thread
		// it will wake up every x seconds and
		// maintain the pool size
		pool.setMaintSleep(30);

		// set some TCP settings
		// disable nagle
		// set the read timeout to 3 secs
		// and don't set a connect timeout
		pool.setNagle(false);
		pool.setSocketTO(3000);
		pool.setSocketConnectTO(0);

		// initialize the connection pool
		pool.initialize();
	}

	public static void main(String[] args) {
		System.out.println("SET: " + mcc.set("key1", "value1"));
		System.out.println("SET: " + mcc.set("key2", "value2"));
		System.out.println("SET: " + mcc.set("key3", "value3"));
		System.out.println("GET: " + mcc.get("key1"));
		MemcachedItem item = mcc.gets("key1");
		System.out.println("GETS: value=" + item.getValue() + ",CasUnique:"+item.getCasUnique());
		System.out.println("SET: " + mcc.set("key1", "value1_1"));
		System.out.println("CAS: " + mcc.cas("key1", "value1_2", item.getCasUnique())); //必须FALSE
		System.out.println("getMulti:" + mcc.getMulti(new String[]{"key1","key2","key3"}));
	}

}

 

 

我的代码

这个标题不好取,因为是我自己的想法,还需要大家多提意见,一起讨论。想叫“建议代码”或者“推荐代码”,觉得不合适,还是先叫“我的代码”吧,呵呵。

 

我的思路

1. 在原始客户端上层,根据业务需求封装MemcachedService(或叫MemcachedClient),负责缓存功能的包装。如:你的业务只需要add,set,get,gets,cas,delete业务,那就只封装这几个功能。这样做的好处是,屏蔽了各种客户端的API差异,让你的业务系统与客户端实现解耦合,如果你以后需要换客户端实现,对你的业务系统不会照成影响。
2.  一般不要直接采用new的方式在你的代码中显示使用memcached客户端实现,应该采用单例的方式使用memcached客户端实现,或者使用Spring的singleton方式配置。Memcached客户端实现是线程安全的。
3. memcached客户端一般都需要大量的配置,考虑扩展和配置修改,应该把参数设置设计为可配置的,可以写到propertis配置文件中或是使用Spring进行配置。

我的实现

业务层封装接口

Java代码  

  1. /** 
  2.  * Memcached 常用功能接口定义,用于业务层直接使用,屏蔽各种客户端实现的API差异,实现解耦客户端与业务系统的目的 
  3.  * 无过期时间和flags支持,无append,prepend,replace,incr,decr等操作 
  4.  *  
  5.  * @author zhangpu 
  6.  *  
  7.  */  
  8. public interface MemcachedClientService {  
  9.   
  10.     String get(String key);  
  11.   
  12.     CacheItem gets(String key);  
  13.   
  14.     boolean add(String key, String value);  
  15.   
  16.     boolean set(String key, String value);  
  17.   
  18.     boolean cas(String key, String value, long unique);  
  19.       
  20.     boolean delete(String key)  
  21.   
  22.     boolean flushAll();  
  23.   
  24. }  
/**
 * Memcached 常用功能接口定义,用于业务层直接使用,屏蔽各种客户端实现的API差异,实现解耦客户端与业务系统的目的
 * 无过期时间和flags支持,无append,prepend,replace,incr,decr等操作
 *
 * @author zhangpu
 *
 */
public interface MemcachedClientService {

	String get(String key);

	CacheItem gets(String key);

	boolean add(String key, String value);

	boolean set(String key, String value);

	boolean cas(String key, String value, long unique);

	boolean delete(String key)

	boolean flushAll();

}

 

Java代码  

  1. public class CacheItem {  
  2.   
  3.     private String key;  
  4.     private String value;  
  5.     private long unique;  
  6.   
  7.     public CacheItem() {  
  8.         super();  
  9.     }  
  10.   
  11.     public CacheItem(String key, String value, long unique) {  
  12.         super();  
  13.         this.key = key;  
  14.         this.value = value;  
  15.         this.unique = unique;  
  16.     }  
  17.   
  18.     public String getKey() {  
  19.         return key;  
  20.     }  
  21.   
  22.     public void setKey(String key) {  
  23.         this.key = key;  
  24.     }  
  25.   
  26.     public String getValue() {  
  27.         return value;  
  28.     }  
  29.   
  30.     public void setValue(String value) {  
  31.         this.value = value;  
  32.     }  
  33.   
  34.     public long getUnique() {  
  35.         return unique;  
  36.     }  
  37.   
  38.     public void setUnique(long unique) {  
  39.         this.unique = unique;  
  40.     }  
  41.   
  42. }  
public class CacheItem {

	private String key;
	private String value;
	private long unique;

	public CacheItem() {
		super();
	}

	public CacheItem(String key, String value, long unique) {
		super();
		this.key = key;
		this.value = value;
		this.unique = unique;
	}

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public String getValue() {
		return value;
	}

	public void setValue(String value) {
		this.value = value;
	}

	public long getUnique() {
		return unique;
	}

	public void setUnique(long unique) {
		this.unique = unique;
	}

}

 

客户端缓存服务实现

 

Java代码  

  1. /** 
  2.  * Memcached for java客户端缓存服务实现 
  3.  * @author zhangpu 
  4.  * 
  5.  */  
  6. public class MemcachedClientJava implements MemcachedClientService {  
  7.   
  8.     MemCachedClient mmc = MemcachedClientFactory.getInstance();  
  9.     public boolean add(String key, String value) {  
  10.         return mmc.add(key, value);  
  11.     }  
  12.   
  13.     public boolean cas(String key, String value, long unique) {  
  14.         return mmc.cas(key, value, unique);  
  15.     }  
  16.   
  17.     public String get(String key) {  
  18.         return (String) mmc.get(key);  
  19.     }  
  20.   
  21.     public CacheItem gets(String key) {  
  22.         MemcachedItem item = mmc.gets(key);  
  23.         return new CacheItem(key, (String) item.getValue(), item.getCasUnique());  
  24.     }  
  25.   
  26.     public boolean set(String key, String value) {  
  27.         return mmc.set(key, value);  
  28.     }  
  29.   
  30.     public boolean delete(String key) {  
  31.         return mmc.delete(key);  
  32.     }  
  33.   
  34.   
  35.     public boolean flushAll() {  
  36.         return mmc.flushAll();  
  37.     }  
  38.       
  39. }  
/**
 * Memcached for java客户端缓存服务实现
 * @author zhangpu
 *
 */
public class MemcachedClientJava implements MemcachedClientService {

	MemCachedClient mmc = MemcachedClientFactory.getInstance();
	public boolean add(String key, String value) {
		return mmc.add(key, value);
	}

	public boolean cas(String key, String value, long unique) {
		return mmc.cas(key, value, unique);
	}

	public String get(String key) {
		return (String) mmc.get(key);
	}

	public CacheItem gets(String key) {
		MemcachedItem item = mmc.gets(key);
		return new CacheItem(key, (String) item.getValue(), item.getCasUnique());
	}

	public boolean set(String key, String value) {
		return mmc.set(key, value);
	}

	public boolean delete(String key) {
		return mmc.delete(key);
	}

	public boolean flushAll() {
		return mmc.flushAll();
	}

}

 

获取客户端实例

Java代码  

  1. /** 
  2.  * MemcachedClient 单例(JDK1.5以上) 
  3.  * @author zhangpu 
  4.  * 
  5.  */  
  6. public class MemcachedClientFactory extends ConfigurableConstants{  
  7.   
  8.     private static volatile MemCachedClient mmc;  
  9.   
  10.     static {  
  11.         init("memcached-client.properties");  
  12.           
  13.         //{ "localhost:11211", "localhost:11212", "localhost:11213" };  
  14.         String[] servers = getProperty("memcached-servers","").split(",");  
  15.   
  16.         Integer[] weights = null;  
  17.         String weightsCfg = getProperty("memcached-weights","");  
  18.         if(weightsCfg != null){  
  19.             String[] wcfg = weightsCfg.split(",");  
  20.             weights = new Integer[wcfg.length];  
  21.             for (int i = 0; i < weights.length; i++) {  
  22.                 weights[i] = Integer.valueOf(wcfg[i]);  
  23.             }  
  24.         }else{  
  25.             weights = new Integer[servers.length];  
  26.             for (int i = 0; i < weights.length; i++) {  
  27.                 weights[i] = 1;  
  28.             }  
  29.         }  
  30.           
  31.         SockIOPool pool = SockIOPool.getInstance();  
  32.   
  33.         pool.setServers(servers);  
  34.         pool.setWeights(weights);  
  35.         pool.setHashingAlg(SockIOPool.CONSISTENT_HASH);  
  36.   
  37.         pool.setInitConn(getProperty("memcached-initConn",5));  
  38.         pool.setMinConn(getProperty("memcached-minConn",5));  
  39.         pool.setMaxConn(getProperty("memcached-maxConn",250));  
  40.         pool.setMaxIdle(1000 * 60 * 60 * 6);  
  41.   
  42.         pool.setMaintSleep(30);  
  43.   
  44.         pool.setNagle(false);  
  45.         pool.setSocketTO(3000);  
  46.         pool.setSocketConnectTO(0);  
  47.   
  48.         pool.initialize();  
  49.     }  
  50.   
  51.     private MemcachedClientFactory() {  
  52.   
  53.     }  
  54.   
  55.     public static MemCachedClient getInstance() {  
  56.         if (mmc == null) {  
  57.             synchronized (MemCachedClient.class) {  
  58.                 if (mmc == null) {  
  59.                     mmc = new MemCachedClient();  
  60.                 }  
  61.             }  
  62.         }  
  63.         return mmc;  
  64.     }  
  65.   
  66. }  
/**
 * MemcachedClient 单例(JDK1.5以上)
 * @author zhangpu
 *
 */
public class MemcachedClientFactory extends ConfigurableConstants{

	private static volatile MemCachedClient mmc;

	static {
		init("memcached-client.properties");

		//{ "localhost:11211", "localhost:11212", "localhost:11213" };
		String[] servers = getProperty("memcached-servers","").split(",");

		Integer[] weights = null;
		String weightsCfg = getProperty("memcached-weights","");
		if(weightsCfg != null){
			String[] wcfg = weightsCfg.split(",");
			weights = new Integer[wcfg.length];
			for (int i = 0; i < weights.length; i++) {
				weights[i] = Integer.valueOf(wcfg[i]);
			}
		}else{
			weights = new Integer[servers.length];
			for (int i = 0; i < weights.length; i++) {
				weights[i] = 1;
			}
		}

		SockIOPool pool = SockIOPool.getInstance();

		pool.setServers(servers);
		pool.setWeights(weights);
		pool.setHashingAlg(SockIOPool.CONSISTENT_HASH);

		pool.setInitConn(getProperty("memcached-initConn",5));
		pool.setMinConn(getProperty("memcached-minConn",5));
		pool.setMaxConn(getProperty("memcached-maxConn",250));
		pool.setMaxIdle(1000 * 60 * 60 * 6);

		pool.setMaintSleep(30);

		pool.setNagle(false);
		pool.setSocketTO(3000);
		pool.setSocketConnectTO(0);

		pool.initialize();
	}

	private MemcachedClientFactory() {

	}

	public static MemCachedClient getInstance() {
		if (mmc == null) {
			synchronized (MemCachedClient.class) {
				if (mmc == null) {
					mmc = new MemCachedClient();
				}
			}
		}
		return mmc;
	}

}

 

参数配置

 

Java代码  

  1. /** 
  2.  
  3.   * 通过 properties 文件配置设置常量基类 负责加载和读取 properties 属性文件并提供访问的静态工具方法 
  4.  
  5.   * 
  6.  
  7.   * @author zhangpu 
  8.  
  9.   * 
  10.  
  11.   */  
  12.   
  13. public class ConfigurableConstants {  
  14.   
  15.       protected static Log logger = LogFactory.getLog(ConfigurableConstants.class);  
  16.   
  17.       protected static Properties p = new Properties();  
  18.   
  19.    
  20.   
  21.       protected static void init(String propertyFileName) {  
  22.   
  23.               InputStream in = null;  
  24.   
  25.               try {  
  26.   
  27.                      in = ConfigurableConstants.class.getClassLoader().getResourceAsStream(propertyFileName);  
  28.   
  29.                      if (in != null)  
  30.   
  31.                              p.load(in);  
  32.   
  33.               } catch (IOException e) {  
  34.   
  35.                      logger.error("load " + propertyFileName + " into Constants error!");  
  36.   
  37.               } finally {  
  38.   
  39.                      if (in != null) {  
  40.   
  41.                              try {  
  42.   
  43.                                     in.close();  
  44.   
  45.                              } catch (IOException e) {  
  46.   
  47.                                     logger.error("close " + propertyFileName + " error!");  
  48.   
  49.                              }  
  50.   
  51.                      }  
  52.   
  53.               }  
  54.   
  55.       }  
  56.   
  57.    
  58.   
  59.       protected static String getProperty(String key, String defaultValue) {  
  60.   
  61.               return p.getProperty(key, defaultValue);  
  62.   
  63.       }  
  64.   
  65.    
  66.   
  67.       protected static int getProperty(String key, int defaultValue) {  
  68.   
  69.               try {  
  70.   
  71.                      return Integer.parseInt(getProperty(key, ""));  
  72.   
  73.               } catch (Exception e) {  
  74.   
  75.                      return defaultValue;  
  76.   
  77.               }  
  78.   
  79.    
  80.   
  81.       }  
  82.   
  83. }  
/**

  * 通过 properties 文件配置设置常量基类 负责加载和读取 properties 属性文件并提供访问的静态工具方法

  *

  * @author zhangpu

  *

  */

public class ConfigurableConstants {

      protected static Log logger = LogFactory.getLog(ConfigurableConstants.class);

      protected static Properties p = new Properties();

      protected static void init(String propertyFileName) {

              InputStream in = null;

              try {

                     in = ConfigurableConstants.class.getClassLoader().getResourceAsStream(propertyFileName);

                     if (in != null)

                             p.load(in);

              } catch (IOException e) {

                     logger.error("load " + propertyFileName + " into Constants error!");

              } finally {

                     if (in != null) {

                             try {

                                    in.close();

                             } catch (IOException e) {

                                    logger.error("close " + propertyFileName + " error!");

                             }

                     }

              }

      }

      protected static String getProperty(String key, String defaultValue) {

              return p.getProperty(key, defaultValue);

      }

      protected static int getProperty(String key, int defaultValue) {

              try {

                     return Integer.parseInt(getProperty(key, ""));

              } catch (Exception e) {

                     return defaultValue;

              }

      }

}

 

配置文件

memcached-client.properties

Properties代码  

  1. memcached-client.properties  
  2. memcached-servers=localhost:11211,localhost:11212,localhost:11213  
  3. memcached-weights=3,3,2  
  4. memcached-initConn=5  
  5. memcached-minConn=5  
  6. memcached-maxConn=250  
memcached-client.properties
memcached-servers=localhost:11211,localhost:11212,localhost:11213
memcached-weights=3,3,2
memcached-initConn=5
memcached-minConn=5
memcached-maxConn=250

 

后续提供性能测试,spring整合,版本差异测试,及其它客户端对比。

时间: 2024-09-01 14:19:17

Memcached学习笔记 — 第四部分:Memcached Java 客户端-gwhalin(1)-介绍及使用的相关文章

Mysql学习笔记(四)字符串函数

原文:Mysql学习笔记(四)字符串函数 PS:终于看完了字符串函数,心都快碎了...涉及的函数真是太多了...感觉这里的字符串函数和JAVA里的基本都差不多了...基本上算是掌握了,但是想全记住那是不太可能的... 学习内容: 字符串函数的掌握和应用.. ASCii(str) 返回字符串的最左边的ascii码值..如果str为NULL,那么返回NULL...如果字符串为0,那么返回也为0...   mysql>select ascii('2'); mysql>select ascii('dx

VSTO学习笔记(四)从SharePoint 2010中下载文件

原文:VSTO学习笔记(四)从SharePoint 2010中下载文件 上一次我们开发了一个简单的64位COM加载项,虽然功能很简单,但是包括了开发一个64位COM加载项的大部分过程.本次我们来给COM加载项添加一些功能:从SharePoint 2010的文档库中下载一个Excel文档到本地. 示例代码下载 本系列所有示例代码均在 Visual Studio 2010 Ultimate RC + Office 2010 Professional Plus Beta x64 上测试通过.   1.

kvm虚拟化学习笔记(十四)之kvm虚拟机静态迁移

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://koumm.blog.51cto.com/703525/1298852 这里提到的静态迁移同是基于KVM虚拟主机之间的迁移,非异构虚拟化平台的静态迁移. 本文出自:http://koumm.blog.51cto.com kvm虚拟化学习笔记(一)之kvm虚拟化环境安装http://koumm.blog.51cto.com/703525/1288795 kvm虚拟化学习笔记(二)之

Akka学习笔记(四):监督和监控

Akka学习笔记(四):监督和监控 Supervision是什么 supervision表示actors之间的关系.监督者分配任务给下属,因此需要处理反馈的错误.根据不同的错误,监督者supervisor可以做如下操作: 恢复下属,让下属继续运行,继续接收message.当且仅当下属还可以正常运行 重启下属,清空status.一般是第一条情况中,child的异常导致无法正常运行. 关闭下属 关闭自己,向上一级汇报错误 上面的操作都是递归的. 警告 supervision发送的是system me

JVM学习笔记(四)------内存调优

首先需要注意的是在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提供的内存查看工具,比如JConsole和Java VisualVM. 对JVM内存的系统级的调优主要的目的是减少GC的频率和Full GC的次数,过多的GC和Full GC是会占用很多的系统资源(主要是CPU),影响系统的吞吐量.特别要关注Full GC,因为它会对整个堆进行整理,导致Full GC

JVM学习笔记(四)------内存调优【转】

转自:http://blog.csdn.net/cutesource/article/details/5907418 版权声明:本文为博主原创文章,未经博主允许不得转载. 首先需要注意的是在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提供的内存查看工具,比如JConsole和Java VisualVM. 对JVM内存的系统级的调优主要的目的是减少GC的频率和Fu

javascript学习笔记(四)function函数部分_基础知识

函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块. Jscript 支持两种函数:一类是语言内部的函数(如eval() ),另一类是自己创建的. 在 JavaScript 函数内部声明的变量(使用 var)是局部变量,所以只能在函数内部访问它.(该变量的作用域是局部的). 您可以在不同的函数中使用名称相同的局部变量,因为只有声明过该变量的函数才能识别出该变量. 函数的调用方式 1.普通调用:functionName(实际参数...) 2.通过指向函数的变量去调用: var  myVar

python网络编程学习笔记(二):socket建立网络客户端_python

1.建立socket 建立socket对象需要搞清通信类型和协议家族.通信类型指明了用什么协议来传输数据.协议的例子包括IPv4.IPv6.IPX\SPX.AFP.对于internet通信,通信类型基本上都是AF_INET(和IPv4对应).协议家族一般表示TCP通信的SOCK_STREAM或者表示UDP通信的SOCK_DGRAM.因此对于TCP通信,建立一个socket连接的语句为:s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)对于UDP通

JVM学习笔记(四)——字节码执行引擎

代码编译的结果从机器码转变为字节码,是存储格式的一小步,确实编程语言发展的一大步.正是因为有了字节码这一中间格式才有了Java语言跨平台的特性. 字节码并不能直接基于物理机执行引擎执行,因为物理机执行引擎是建立在特定的处理器,指令集以及操作系统之上的,并不具备跨平台特性.所以执行字节码的责任就交给了虚拟机中的字节码执行引擎. 1 运行时栈帧结构 栈帧是用于刻画Java程序运行时一个方法的调用.执行以及返回过程的数据结构.通过学习前面的博客我们知道Java程序运行时有一块区域叫做虚拟机栈,而虚拟机