Java多线程编程核心技术(第3版)
上QQ阅读APP看书,第一时间看更新

2.2.17 String常量池特性与同步问题

JVM具有String常量池的功能,所以如图2-48所示的结果为true。

图2-48 String常量池缓存

在将synchronized(string)同步块与String联合使用时,要注意常量池会带来一些意外。

新建名称为StringAndSyn的项目,类文件Service.java代码如下:


package service;

public class Service {
public static void print(String stringParam) {
    try {
        synchronized (stringParam) {
            while (true) {

            System.out.println(Thread.currentThread().getName());
                Thread.sleep(1000);
            }
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
        }
}
}

两个自定义线程代码如图2-49所示。

运行类Run.java代码如下:


package test;

import service.Service;
import extthread.ThreadA;
import extthread.ThreadB;

public class Run {

public static void main(String[] args) {

    Service service = new Service();

    ThreadA a = new ThreadA(service);
    a.setName("A");
    a.start();

    ThreadB b = new ThreadB(service);
    b.setName("B");
    b.start();

}

}

图2-49 线程类代码

程序运行结果如图2-50所示。

图2-50 死循环

出现这种情况就是因为String的两个值都是”AA”,两个线程是持有相同的锁,造成线程B不能执行。这就是String常量池所带来的问题,所以大多数情况下,同步synchronized代码块都不使用String作为锁对象,而改用其他,例如new Object()实例化一个新的Object对象时,它并不放入缓存池中,或者执行new String()创建不同的字符串对象,形成不同的锁。

继续实验,创建名称为StringAndSyn2的项目,类文件Service.java代码如下:


package service;

public class Service {
public static void print(Object object) {
    try {
        synchronized (object) {
            while (true) {

                System.out.println(Thread.currentThread().getName());
                Thread.sleep(1000);
            }
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
}

两个自定义线程如图2-51所示。

图2-51 自定义线程代码

运行类Run.java代码如下:


package test;

import service.Service;
import extthread.ThreadA;
import extthread.ThreadB;

public class Run {

public static void main(String[] args) {

    Service service = new Service();

    ThreadA a = new ThreadA(service);
    a.setName("A");
    a.start();

    ThreadB b = new ThreadB(service);
    b.setName("B");
    b.start();

}

}

程序运行结果如图2-52所示。

图2-52 交替输出

交替输出的原因是持有的锁不是一个。