前言
使用static关键词描述变量在内存中只有一份,是是一个共享全局变量。对于对象来说是单例的。
在之前的文章中描述过enum在使用过程中遇到的问题:
http://blog.csdn.net/xiaoxiaoxuanao/article/details/52573863
因为枚举实际上是单例的,如果试图去修改枚举里对象的属性值,可能会引发访问问题。
就我目前的开发经验来看,对象单例一般有两种方式创建
使用static关键词,显式的创建单例对象
http://blog.csdn.net/xiaoxiaoxuanao/article/details/52573879使用枚举,隐式创建单例对象
既然单例在内存中只有一份,那么什么时候要使用,什么时候不能使用呢?
不能使用static对象的情况
平时在做web开发的过程中经常会看到有程序员写出类似于下面的代码:
@Controller
@RequestMapping("example")
public class ExampleController {
private static Integer index = 0;
@RequestMapping("test")
public void addIndex(){
index++;
}
}
这段代码在单个client访问的时候不会有任何问题,因为每访问一次index就会加1,但是多个client访问的时候,不同的client的访问会导致index的值彼此影响;另外一个是多个客户端并发访问的时候index的值会出现不确定的情况。
总结1:不要试图改变共享的全局变量的属性值或者值,如果有类似的需求,最好封装在单个线程内部去做。
务必使用static的情况
static的对象在内存中只有一份,所以那些资源性的东西,比方说HttpClient,redisResource,curatorclient非常适合建立static的对象,这样保证对象在内存中只有一份。这种在内存中只有一份的对象有很多好处:
- 可以大大节省请求的访问时间,因为避免了每次使用资源的时候都去建立连接或者创建对象
- 相比于在方法内创建对象,单例对象不会随着方法的退出被jvm回收掉,因而那种需要永久保留的对象都要创建成static的
- 资源只有一份的时候方便jvm对象的回收,此时jvm只需要回收一次,而那种每次需要资源时都创建对象的方式往往需要使用完后手动执行关闭比方说下面的代码:
public String setExpire(String cacheKey, int validTimeInSeconds, String value){
Jedis redis = getResource();
String resultData = null;
try {
resultData = redis.setex(cacheKey, validTimeInSeconds, value);
this.lastVisitCache.set(cacheKey, value);
} catch (Exception e) {
LOGGER.error("{}", e.getMessage(), e);
} finally {
returnResource(redis);
}
return resultData;
}
例子:
(1)创建curatorframework对象:
public abstract class PathCacheExample {
private static final String PATH = "/example";
static CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", new ExponentialBackoffRetry(1000, 3));
static PathChildrenCache cache = new PathChildrenCache(client, PATH, true);
static TreeCache treeCache = new TreeCache(client, PATH);
public static void main(String[] args) {
start();
}
public static void start() {
try {
client.start();
cache.start();
treeCache.start();
addPathChildListener(cache);
//addTreeListener(treeCache);
//processCommands(client, cache);
} catch (Exception e) {
e.printStackTrace();
}
}
public void shutdown() {
CloseableUtils.closeQuietly(cache);
CloseableUtils.closeQuietly(client);
}
}
(2)httpclient对象的创建:
public class HttpClientBasedQdContactFetcher implements QdContactFetcher {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientBasedQdContactFetcher.class);
private static final CloseableHttpClient closeableHttpClient = buildClient();
private CloseableHttpClient buildClient() {
String hostName = "127.0.0.1";
int port = 3128;
SocketConfig socketConfig = SocketConfig.custom()
.setSoTimeout(3000)
.setSoKeepAlive(false)
.setSoReuseAddress(false)
.build();
HttpHost proxy = new HttpHost(hostName, port);
return HttpClientBuilder.create()
.setDefaultSocketConfig(socketConfig)
.setProxy(proxy)
.build();
}
总结2:那些不变的,耗时的,不能创建太多的,不希
望被回收的对象都要创建成static的。