我是靠谱客的博主 懵懂荔枝,这篇文章主要介绍synchronized(string)1. 前言2. new String()3. StringBulider和StringBuffer4. 解决方法,现在分享给大家,希望可以做个参考。

这里写自定义目录标题

  • 1. 前言
  • 2. new String()
  • 3. StringBulider和StringBuffer
  • 4. 解决方法

1. 前言

String是Java中的一种特殊类型,String在创建后存入字符串常量池。
利用这个特征,可以使用String作为同步锁。例如,在更新用户信息时,可以使用用户的名称作为同步锁,不同的用户可以使用不同的锁来提高并发性能。这个特征扩展适当的场景非常多。

2. new String()

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class TestStringSync { private static Integer CNT = 0; public static void main(String[] args) { final String lock = new String(ObjectId.get().toString()); run(lock); } private static void run(String lock) { final Integer threadNum = 10; final CyclicBarrier cb = new CyclicBarrier(threadNum, new Runnable() { public void run() { System.out.println("threadNum : " + threadNum); } }); for(int i = 0; i< threadNum; i++) { String tmpLock = new String(lock); new TestThread(cb, tmpLock.toString()).start(); } } static class TestThread extends Thread { private CyclicBarrier cbLock; private String lock; public TestThread(CyclicBarrier cbLock, String lock) { this.cbLock = cbLock; this.lock = lock; } public void run() { try { cbLock.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(lock) { //这里直接使用String对象本身作为锁 CNT = CNT+1; System.out.println("Value:" + CNT); } } } }
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
threadNum : 10 Value:2 Value:2 Value:2 Value:2 Value:4 Value:5 Value:5 Value:4 Value:4 Value:4

从结果可以看出,每个线程创建前使用new String(lock)会产生不同的锁,造成线程同步失败。所以在使用的时候要特别注意这点,new String(lock)是会产生不同的对象,他们所指向的对象锁是不同的。

3. StringBulider和StringBuffer

复制代码
1
2
3
4
5
6
7
StringBuilder tmpLock = new StringBuilder(); tmpLock.append("user name"); tmpLock.append("org name"); for(int i = 0; i< threadNum; i++) { new TestThread(cb, tmpLock.toString()).start(); }
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
threadNum : 10 Value:2 Value:2 Value:2 Value:3 Value:2 Value:3 Value:2 Value:3 Value:2 Value:2

可见,这个锁还是不行。原因是StringBuiler的toString方法中返回的是new String,代码如下:

复制代码
1
2
3
4
5
6
@Override public String toString() { // Create a copy, don't share the array return new String(value, 0, count); }

这就导致线程拿到的还是不同的字符串对象。

4. 解决方法

针对上面举的例子可以发现,使用String作为同步锁必须注意产生不同对象的问题,必须保证线程拿到的是同一个String对象。做法最简单的就是使用同一个String对象,但这个有时很难保证。特别是我们很多的时候代码是分布式环境下的。

比如,我们将用户名存在了redis里,线程每次同步的时候去redis里取一下数据,这样就很有可能导致产生新的String对象。这个时候就得使用intern()方法。上面的代码修改为:

复制代码
1
2
3
4
5
synchronized(lock.intern()) { CNT = CNT+1; System.out.println("Value:" + CNT); }

这样就是直接获取的是字符串的值本身,而不是取的String的对象,以此保证同一个字符串拿到的是同一个String对象,自然在同一个进程中就是同一个对象锁了。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
threadNum : 10 Value:1 Value:2 Value:3 Value:4 Value:5 Value:6 Value:7 Value:8 Value:9 Value:10

来源:http://t.zoukankan.com/5207-p-9592516.html
String.intern():https://blog.csdn.net/tyyking/article/details/82496901

最后

以上就是懵懂荔枝最近收集整理的关于synchronized(string)1. 前言2. new String()3. StringBulider和StringBuffer4. 解决方法的全部内容,更多相关synchronized(string)1.内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部