关于synchronized锁String
关于synchronized锁String
今天遇到的面试官提问了相关的问题:
使用synchronized关键字锁String参数对象的情况下,能不能保证线程安全
当时的想法(脑子已浆糊):
String类由final修饰,不可变
Java只有值传递,只要比较String对象引用的内存地址是否一致
测试代码
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* MySynchronizedTest
*
* @author <b>孤寂灬无痕</b>
* <p>
* 994300880@qq.com
* @version 1.0
* @date 2024/4/16 12:10
*/
public class MySynchronizedTest {
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(4, 8, 5L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(4), new ThreadFactory() {
private final AtomicInteger id = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("myThreadPool - " + id.getAndIncrement());
return thread;
}
});
for (int i = 1; i < 5; i++) {
threadPool.execute(new MyTestThread3("任务 - " + i));
}
//阻塞主线程
System.out.println("主线程阻塞...");
Thread.sleep(5000L);
//关闭线程池
threadPool.shutdown();
// 等待所有任务执行完毕
while(!threadPool.awaitTermination(2L, TimeUnit.SECONDS)){
System.out.println("线程池未关闭!");
}
System.out.println("主线程结束!");
}
}
//第一种情况
record MyTestThread(String taskName) implements Runnable {
@Override
public void run() {
String name = Thread.currentThread().getName();
synchronized (name) {
System.out.println(name + " 开始执行任务!");
try {
//睡1秒
Thread.sleep(1000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(name + " 结束任务!");
}
}
}
//第二种情况
record MyTestThread2(String taskName) implements Runnable {
@Override
public void run() {
String name = Thread.currentThread().getName();
String s = "a";
synchronized (s) {
System.out.println(name + " 开始执行任务!");
try {
//睡1秒
Thread.sleep(1000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(name + " 结束任务!");
}
}
}
//第三种情况
record MyTestThread3(String taskName) implements Runnable {
@Override
public void run() {
String name = Thread.currentThread().getName();
String s = new String("a");
synchronized (s) {
System.out.println(name + " 开始执行任务!");
try {
//睡1秒
Thread.sleep(1000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(name + " 结束任务!");
}
}
}
第一种:值不一样
主线程阻塞...
myThreadPool - 1 开始执行任务!
myThreadPool - 2 开始执行任务!
myThreadPool - 3 开始执行任务!
myThreadPool - 4 开始执行任务!
myThreadPool - 3 结束任务!
myThreadPool - 2 结束任务!
myThreadPool - 4 结束任务!
myThreadPool - 1 结束任务!
主线程结束!
第二种:值一样,内存地址一样
主线程阻塞...
myThreadPool - 1 开始执行任务!
myThreadPool - 1 结束任务!
myThreadPool - 4 开始执行任务!
myThreadPool - 4 结束任务!
myThreadPool - 3 开始执行任务!
myThreadPool - 3 结束任务!
myThreadPool - 2 开始执行任务!
myThreadPool - 2 结束任务!
主线程结束!
第三种:值一样,内存地址不一样
主线程阻塞...
myThreadPool - 1 开始执行任务!
myThreadPool - 4 开始执行任务!
myThreadPool - 3 开始执行任务!
myThreadPool - 2 开始执行任务!
myThreadPool - 4 结束任务!
myThreadPool - 1 结束任务!
myThreadPool - 3 结束任务!
myThreadPool - 2 结束任务!
主线程结束!
总结
String类由final修饰,不可变
Java只有值传递,只要比较String对象引用的内存地址是否一致
通过内存地址判断是不是同一个对象
涉及字符串常量池和String.intern()方法
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 孤寂灬无痕
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果