程序计数器
程序计数器在java代码运行的过程中有着至关重要的功能,如果没有程序计数器,Java程序中的流程控制将无法得到正确的控制,多线程也无法正确的轮换。关于程序计数器的详细解说,请参考这篇文章
实例代码:
public class PCRegisterTest {
public static void main(String[] args) {
int a = 10;
int b = 20;
String c = "123";
System.out.println(c);
System.out.println(b-a);
}
}
字节码文件:
/**
* Constant pool:
* #1 = Methodref #7.#26 // java/lang/Object."<init>":()V
* #2 = String #27 // 123 (常量池)
* #27 = Utf8 123 // 获取123的值
* #37 = Utf8 Ljava/io/PrintStream;
* {
* public CrazyTest.PcRegister.PCRegisterTest();
* descriptor: ()V
* flags: ACC_PUBLIC
* Code:
* stack=1, locals=1, args_size=1
* 0: aload_0
* 1: invokespecial #1 // Method java/lang/Object."<init>":()V
* 4: return
* LineNumberTable:
* line 3: 0
* LocalVariableTable:
* Start Length Slot Name Signature
* 0 5 0 this LCrazyTest/PcRegister/PCRegisterTest;
*
* public static void main(java.lang.String[]);
* descriptor: ([Ljava/lang/String;)V
* flags: ACC_PUBLIC, ACC_STATIC
* Code:
* stack=3, locals=4, args_size=1
* 0: bipush 10
* 2: istore_1
* 3: bipush 20
* 5: istore_2
* 6: ldc #2 // String 123
* 8: astore_3
* 9: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
* 12: aload_3
* 13: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
* 16: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
* 19: iload_2
* 20: iload_1
* 21: isub
* 22: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
* 25: return
* LineNumberTable:
* line 5: 0
* line 6: 3
* line 8: 6
* line 9: 9
* line 10: 16
* line 11: 25
* LocalVariableTable:
* Start Length Slot Name Signature
* 0 26 0 args [Ljava/lang/String;
* 3 23 1 a I
* 6 20 2 b I
* 9 17 3 c Ljava/lang/String;
* }
* SourceFile: "PCRegisterTest.java"
*/
PC寄存器的存储字节码指令的用途:当程序运行时,CPU需要不断切换其他的线程,当CPU切换回原来的线程时,CPU就知道从哪里开始执行。
PC寄存器记录当前线程的执行地址:JVM的字节码解析器需要改变PC寄存器的值来明确下一条该执行什么样的字节码指令。
PC寄存器被设定为线程私有:CPU在运行的过程中不断做任务切换,多线程是在一个时间段内只会执行其中的某一个线程的方法,这样必然会有中断和异常,为了准确记录各个线程正在执行的当前字节码指令地址,那就必须每一个线程配备一个PC寄存器,这样线程可以独立计算,不会互相干扰。
由于CPU时间片限制,众多线程在并发执行过程中,任何一个确定的时刻,一个处理器或者多核处理器中的一个内核,只会执行某一个线程的字节码指令。这样需要给每一个线程在创建的时候,分配一个程序计数器和栈帧,程序计数器在各个线程中互不影响。
CPU时间片:CPU分配给各个程序的时间,每一个线程被分配一个时间段,称作时间片。用户可以打开多个程序同时运行,在视觉错觉上以为是并发运行的,但是实际上由于只有一个CPU,一次只能处理程序要求的一部分,如何实现公平处理,那就是引用时间片,让每一个程序轮流执行。