Java中String做为synchronized同步锁
synchronized (("" + userId).intern()) {
// TODO:something
}
JVM内存区域里面有一块常量池,关于常量池的分配:
- JDK6的版本,常量池在持久代PermGen中分配
- JDK7的版本,常量池在堆Heap中分配
字符串是存储在常量池中的,有两种类型的字符串数据会存储在常量池中:
- 编译期就可以确定的字符串,即使用""引起来的字符串,比如String a = "123"、String b = "1" + B.getStringDataFromDB() + "2" + C.getStringDataFromDB()、这里的"123"、"1"、"2"都是编译期间就可以确定的字符串,因此会放入常量池,而B.getStringDataFromDB()、C.getStringDataFromDB()这两个数据由于编译期间无法确定,因此它们是在堆上进行分配的
- 使用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同步锁的更多相关文章
- Java中String做为synchronized同步锁使用详解
Java中使用String作同步锁 在Java中String是一种特殊的类型存在,在jdk中String在创建后是共享常量池的,即使在jdk1.8之后实现有所不同,但是功能还是差不多的. 借助这个特点 ...
- Java中使用CountDownLatch进行多线程同步
CountDownLatch介绍 在前面的Java学习笔记中,总结了Java中进行多线程同步的几个方法: 1.synchronized关键字进行同步. 2.Lock锁接口及其实现类ReentrantL ...
- java中String、StringBuffer、StringBuilder的区别
java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题.现在总结一下,看看他们的不同与相同. 1.可变与不可 ...
- java中String类型变量的赋值问题
第一节 String类型的方法参数 运行下面这段代码,其结果是什么? package com.test; public class Example { String str = new String( ...
- Java基础知识(JAVA中String、StringBuffer、StringBuilder类的区别)
java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题.现在总结一下,看看他们的不同与相同. 1.可变与不可 ...
- Java基础——java中String、StringBuffer、StringBuilder的区别
(转自:http://www.cnblogs.com/xudong-bupt/p/3961159.html) java中String.StringBuffer.StringBuilder是编程中经常使 ...
- 探秘Java中String、StringBuilder以及StringBuffer
探秘Java中String.StringBuilder以及StringBuffer 相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问 到的地方,今天就来和大家一起学习 ...
- java中String类、StringBuilder类和StringBuffer类详解
本位转载自http://www.cnblogs.com/dolphin0520/p/3778589.html 版权声明如下: 作者:海子 出处:http://www.cnblogs.com/dolp ...
- 【转载】 Java中String类型的两种创建方式
本文转载自 https://www.cnblogs.com/fguozhu/articles/2661055.html Java中String是一个特殊的包装类数据有两种创建形式: String s ...
随机推荐
- VsCode安装Go的相关插件
今天在学习Go的时候,安装Go的相关插件,显示安装不上,但是右下角也一直会提示让你安装,当然你可以设置成忽略,为了开发效率,我选择了安装.然后出现了问题,一直Failed.在网上看到了很多的文章,不是 ...
- 【概率论】5-1:分布介绍(Special Distribution Introduction)
title: [概率论]5-1:分布介绍(Special Distribution Introduction) categories: - Mathematic - Probability keywo ...
- Java枚举抽象方法实战
需求背景 需求已经确定了几个固定的常量值,并且每个常量值都有相同的行为,但是具体实现细节不同.建议使用枚举抽象方法,优点:结构清晰,便于扩展. 枚举类实现抽象方法 与常规抽象类一样,enum类允许我们 ...
- Java学习日记——基础篇(二)基本语法
变量 变量和常量是程序处理的两种基本数据对象,变量是程序的基本组成单位 变量的目的就是确定目标并提供存放空间 public class Hello { public static void main( ...
- js 根据滚动条加载数据
很久没记笔记了,最近搞起web开发了 <html> <head> <script src="http://code.jquery.com/jquery-1.7. ...
- elasticsearch配置jdk
编辑bin/elasticsearch 可以看到elasticsearch使用环境变量JAVA_HOME中配置的jdk:if [ -x "$JAVA_HOME/bin/java" ...
- Go by Example-流控制语句之if/else
Go by Example-流控制语句之if/else Go中的if/else的用法和其他语言没什么区别,在格式要求上保留了类似Python中的一些特性. 基本概念 在条件判断语法 if/else 中 ...
- 20175234 2018-2019-2 《Java程序设计》第十周学习总结
目录 20175234 2018-2019-2 <Java程序设计>第十周学习总结 教材学习内容总结 12.1进程与线程 12.2 Java中的线程 12.3 Thread类与线程的创建 ...
- 6.linux 用户和权限的建立
一.用户和权限的建立 su 用户名 切换用户,如果是root用户切换其他用户,不需要输入密码. exit 可以切换回上一个用户 linux 操作系统用户 ...
- CV_Learn
CV学习进度条记录,也是SRTP的进度记录. 阶段一(2019.4-2019.5): 1.opencv简单操作学习.(实现了一些基础操作,从颜色通道到边缘轮廓,2019.4.22完成) 2.linux ...