synchronized (("" + userId).intern()) {
// TODO:something
}

JVM内存区域里面有一块常量池,关于常量池的分配:

  1. JDK6的版本,常量池在持久代PermGen中分配
  2. JDK7的版本,常量池在堆Heap中分配

字符串是存储在常量池中的,有两种类型的字符串数据会存储在常量池中:

  1. 编译期就可以确定的字符串,即使用""引起来的字符串,比如String a = "123"String b = "1" + B.getStringDataFromDB() + "2" + C.getStringDataFromDB()、这里的"123"、"1"、"2"都是编译期间就可以确定的字符串,因此会放入常量池,而B.getStringDataFromDB()、C.getStringDataFromDB()这两个数据由于编译期间无法确定,因此它们是在堆上进行分配的
  2. 使用String的intern()方法操作的字符串,比如String b = B.getStringDataFromDB().intern(),尽管B.getStringDataFromDB()方法拿到的字符串是在堆上分配的,但是由于后面加入了intern(),因此B.getStringDataFromDB()方法的结果,会写入常量池中

常量池中的String数据有一个特点:每次取数据的时候,如果常量池中有,直接拿常量池中的数据;如果常量池中没有,将数据写入常量池中并返回常量池中的数据

这个在jdk6里问题不算大,因为String.intern()会在perm里产生空间,如果perm空间够用的话,这个不会导致频繁Full GC,

但是在jdk7里问题就大了,String.intern()会在heap里产生空间,而且还是老年代,如果对象一多就会导致Full GC时间超长!!!

慎用啊!解决办法?终于找到了。

这里要引用强大的google-guava包,这个包不是一般的强大,是完全要把apache-commons*取缔掉的节奏啊!!!

Interner<String> pool = Interners.newWeakInterner();

synchronized ( pool.intern("BizCode"+userId)){

//TODO:something

}

该类对 intern 做了很多的优化,使用弱引用包装了你传入的字符串类型,所以,这样就不会对内存造成较大的影响, 可以使用该类的 pool.intern(str) 来进行对字符串intern, 好了,这样就解决了内存的问题了,那么我们使用了该优点,并且避免了内存占用问题,完美解决。但这种在分布式系统中会有问题

//类1- SynStringTest
package com.tinygao.thread.synstring; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer; import com.google.common.base.Stopwatch;
import com.google.common.util.concurrent.ThreadFactoryBuilder; import lombok.extern.slf4j.Slf4j; @Slf4j
public class SynStringTest { private final static SynString synStr = new SynString();
private final static Stopwatch sw = Stopwatch.createStarted();
private static BiConsumer<SynString, String> function = (x, y)->{
synchronized (x.getStringLock(y)) {
log.info("Get lock: {}", y);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
public static void main(String[] args) throws InterruptedException {
final ExecutorService executorService = Executors.newFixedThreadPool(
4,
new ThreadFactoryBuilder().setNameFormat("SynString-%d").build()
); executorService.submit(()->{
doTask("test");
});
executorService.submit(()->{
doTask("test");
});
executorService.submit(()->{
doTask("test1");
});
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.DAYS);
sw.stop();
} private static void doTask(String lockStr) {
function.accept(synStr, lockStr);
log.info("Do get lockStr successed waste time elapsed : {} ms", sw.elapsed(TimeUnit.MILLISECONDS));
}
} //类2- SynString
package com.tinygao.thread.synstring;
import java.util.concurrent.ConcurrentMap;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j; @Slf4j
public class SynString { private static ConcurrentMap<String,Object> parMap = Maps.newConcurrentMap(); public Object getStringLock(String string) {
Object lock = this;
if(parMap != null) {
Object newLock = new Object();
lock = parMap.putIfAbsent(string, newLock);
if(lock == null) {
lock = newLock;
}
}
return lock;
} public static void main(String[] args) {
Object result = parMap.putIfAbsent("h", "g");
log.info("Get result: {}", result);
}
}

Java中String做为synchronized同步锁的更多相关文章

  1. Java中String做为synchronized同步锁使用详解

    Java中使用String作同步锁 在Java中String是一种特殊的类型存在,在jdk中String在创建后是共享常量池的,即使在jdk1.8之后实现有所不同,但是功能还是差不多的. 借助这个特点 ...

  2. Java中使用CountDownLatch进行多线程同步

    CountDownLatch介绍 在前面的Java学习笔记中,总结了Java中进行多线程同步的几个方法: 1.synchronized关键字进行同步. 2.Lock锁接口及其实现类ReentrantL ...

  3. java中String、StringBuffer、StringBuilder的区别

    java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题.现在总结一下,看看他们的不同与相同. 1.可变与不可 ...

  4. java中String类型变量的赋值问题

    第一节 String类型的方法参数 运行下面这段代码,其结果是什么? package com.test; public class Example { String str = new String( ...

  5. Java基础知识(JAVA中String、StringBuffer、StringBuilder类的区别)

    java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题.现在总结一下,看看他们的不同与相同. 1.可变与不可 ...

  6. Java基础——java中String、StringBuffer、StringBuilder的区别

    (转自:http://www.cnblogs.com/xudong-bupt/p/3961159.html) java中String.StringBuffer.StringBuilder是编程中经常使 ...

  7. 探秘Java中String、StringBuilder以及StringBuffer

    探秘Java中String.StringBuilder以及StringBuffer 相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问 到的地方,今天就来和大家一起学习 ...

  8. java中String类、StringBuilder类和StringBuffer类详解

    本位转载自http://www.cnblogs.com/dolphin0520/p/3778589.html  版权声明如下: 作者:海子 出处:http://www.cnblogs.com/dolp ...

  9. 【转载】 Java中String类型的两种创建方式

    本文转载自 https://www.cnblogs.com/fguozhu/articles/2661055.html Java中String是一个特殊的包装类数据有两种创建形式: String s ...

随机推荐

  1. learning scala generic classes

    package com.aura.scala.day01 object genericClasses { def main(args: Array[String]): Unit = { val sta ...

  2. 【luogu1251】餐巾计划问题--网络流建模,费用流

    题目描述 一个餐厅在相继的 N 天里,每天需用的餐巾数不尽相同.假设第 iii 天需要 ri​块餐巾( i=1,2,...,N).餐厅可以购买新的餐巾,每块餐巾的费用为 p 分;或者把旧餐巾送到快洗部 ...

  3. 代码 | 自适应大邻域搜索系列之(6) - 判断接受准则SimulatedAnnealing的代码解析

    前言 前面三篇文章对大家来说应该很简单吧?不过轻松了这么久,今天再来看点刺激的.关于判断接受准则的代码.其实,判断接受准则有很多种,效果也因代码而异.今天介绍的是模拟退火的判断接受准则.那么,相关的原 ...

  4. LeetCode 第 150 场周赛

    一.拼写单词(LeetCode-1160) 1.1 题目描述 1.2 解题思路 由于给定的chars,每个字母只能用一次,所以用大小为26的数组charsArray来表示a-z(例如charsArra ...

  5. JavaScript数字精度丢失的一些问题

    本文分为三个部分 JS 数字精度丢失的一些典型问题 JS 数字精度丢失的原因 解决方案(一个对象+一个函数) 一.JS数字精度丢失的一些典型问题 1. 两个简单的浮点数相加 1 0.1 + 0.2 ! ...

  6. main方法的详解

    格式 * public static void main(String[] args) {} 针对格式的解释 public 被jvm调用,访问权限足够大. static 被jvm调用,不用创建对象,直 ...

  7. [Java复习] 分布式PRC - Dubbo

    分布式RPC框架 dubbo常见问题: 1. 问dubbo的工作原理:服务注册,注册中心,服务生产者,消费者,代理通信,负载均衡 2. 问网络通信,序列化: dubbo协议,长连接,NIO,hessi ...

  8. Linux系列之——tomcat 的开机自启动

    --未验证 每次开机都要启动tomcat,非常麻烦:通过直接修改系统文件,实现tomcat自启动: 1. 修改脚本文件rc.local:vim /etc/rc.d/rc.local 这个脚本是使用者自 ...

  9. osg qt fbx ifc bim osg ive 3ds max rvt

    项目环境变量配置 include E:\Qt\Qt5.12.2\5.12.2\msvc2017_64\include E:\OpenSourceGraph\OpenSceneGraph_install ...

  10. Chrome浏览器控制网速的方法