Java中String做为synchronized同步锁
2023-09-11 14:20:10 时间
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多线程之线程同步
- kubernetes-client/java:Scale报错400 BadRequest 或 500 cannot unmarshal object
- C03-Java同步实践加强班第12周上机任务
- Java核心技术卷I基础知识导读
- 监听器-java同步的基本思想
- Java: 环境变量 系统变量 getResource() getResources() getSystemResource()
- 设计模式java——桥接模式
- jvm之java内存区域(一)
- Java 内存溢出(java.lang.OutOfMemoryError)的常见情况和处理方式总结
- 【Java】整理关于java的String类,equals函数和比较操作符的区别
- Java-struts2的问题 java.lang.NoClassDefFoundError: org/apache/commons/lang3/StringUtils
- java两种同步机制的实现 synchronized和reentrantlock
- 《Java和Android开发实战详解》——导读
- java中驼峰与下横线格式字符串互转算法
- 1. java.util.concurrent - Java 并发工具包
- java类路径classpath和包
- Java消息队列
- CXF错误:Unsupported major.minor version 51.0,java.lang.UnsupportedClassVersionErro
- Java学习-040-级联删除目录中的文件、目录
- java中的Volatile关键字使用
- Java多线程-线程的同步与锁
- 十个部分介绍关于Java大致的学习方向
- Linux系统小技巧(1):/dev/random设备可能导致java程序启动慢或者操作耗时不正常
- Java学习---JAVA的类设计
- java比较语句常犯错误和三个数比较大小
- 用notepad++ 打造轻量级Java编译器
- Java Socket与操作系统的关系
- Android(java)同步方法synchronized
- [java][db]JAVA分布式事务原理及应用
- Java并发包中的同步队列SynchronousQueue实现原理
- Java线程同步
- Java线程同步与锁