Java多线程问题--数据类型String的常量池特性

本文内容部分引自《Java多线程编程核心技术》,感谢作者!!!

代码地址:https://github.com/xianzhixianzhixian/thread.git

什么是常量池

这里单单只说Java常量池,Java中的常量池,实际上分为两种形态:静态常量池运行时常量池

     所谓静态常量池,即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分空间。这种常量池主要用于存放两大类常量:字面量(Literal)和符号引用量(Symbolic References),字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等,符号引用则属于编译原理方面的概念,包括了如下三种类型的常量:

  • 类和接口的全限定名
  • 字段名称和描述符
  • 方法名称和描述符

     而运行时常量池,则是jvm虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。

运行时常量池相对于CLass文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入CLass文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用比较多的就是String类的intern()方法。

String的intern()方法会查找在常量池中是否存在一份equal相等的字符串,如果有则返回该字符串的引用,如果没有则添加自己的字符串进入常量池。

再说说String str="a"和String str=new String("a")的区别

经常有一些面试题会问

String a = "a"; String  b = "a"; String c = new String("a");  String d = new String("a");  那么 a==b和c==d的结果分别是什么?

答案是:a==b是true,而c==d是false。为什么呢?

1、==符号比较的是两个数据的地址。

2、a==b为true的原因很显然,是String常量池的问题。

3、c==d为false是因为,String c=new String("a");这段语句的真实意思是“把new出来的String对象地址分配给c”,c变量其实存放的是是new出来的String对象的地址,存放在栈中。而new 出来的String对象是内容,存放在堆中。同理可以类比Integer i=1和Integer k=new Integer(1)的区别,其实和String一样。

接下来讨论String常量池结合线程的问题

StringTest.java

package thread.synchronize.string;

/**
 * 探究String的常量池特性在多线程中的影响
 * @author: xianzhixianzhixian
 * @date: 2018-12-18 20:32
 */
public class StringTest {

    public void testStringSync(String str){
        synchronized(str){
            try {
                System.out.println("线程"+Thread.currentThread().getName()+"运行开始");
                Thread.sleep(1000);
                System.out.println("线程"+Thread.currentThread().getName()+"运行结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

ThreadA.java

package thread.synchronize.string;

/**
 * @author: xianzhixianzhixian
 * @date: 2018-12-18 20:30
 */
public class ThreadA extends Thread {

    private StringTest test;

    public ThreadA(StringTest test) {
        this.test = test;
    }

    @Override
    public void run() {
        super.run();
        test.testStringSync(new String("AA"));
    }
}

ThreadB.java

package thread.synchronize.string;

/**
 * @author: xianzhixianzhixian
 * @date: 2018-12-18 20:30
 */
public class ThreadB extends Thread {

    private StringTest test;

    public ThreadB(StringTest test) {
        this.test = test;
    }

    @Override
    public void run() {
        super.run();
        test.testStringSync("AA");
    }
}

ThreadC.java

package thread.synchronize.string;

/**
 * @author: xianzhixianzhixian
 * @date: 2018-12-18 20:30
 */
public class ThreadC extends Thread {

    private StringTest test;

    public ThreadC(StringTest test) {
        this.test = test;
    }

    @Override
    public void run() {
        super.run();
        test.testStringSync("AA");
    }
}

Run.java

package thread.synchronize.string;

/**
 * @author: xianzhixianzhixian
 * @date: 2018-12-18 20:35
 */
public class Run {

    public static void main(String[] args) {
        StringTest testStr = new StringTest();
        ThreadA threadA = new ThreadA(testStr);
        threadA.setName("a");
        ThreadB threadB = new ThreadB(testStr);
        threadB.setName("b");
        ThreadC threadC = new ThreadC(testStr);
        threadC.setName("c");
        threadA.start();
        threadB.start();
        threadC.start();
    }
}

运行结果:线程a和线程c是同步运行的,而线程b和其它线程是异步运行的,这也说明了String常量池和new String()对线程运行的影响以及两者间的区别

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值