Java并发编程 JUC 线程的创建
进程和线程的区别
进程:进程是cpu资源分配的最小单位,有自己独立的内存空间
线程:线程是cpu调度的最小单位,共享进程的内存空间,一个进程在运行的过程中可以产生多个进程,线程在切换时消耗的资源远小于进程的切换
在Java中,创建一个线程的方法有很多种,可以通过复写父类的run()方法进行创建,也可以创建Runnable对象进行创建
import lombok.extern.slf4j.Slf4j;
/**
* Thread 测试类
*/
@Slf4j(topic = "c.ThreadTest1")
public class ThreadTest1 {
public static void main(String[] args) {
Thread t1 = new Thread("First Thread"){
@Override
public void run() {
log.debug("t1 is running");
}
};
Runnable task1 = new Runnable() {
@Override
public void run() {
log.debug("t2 is running");
}
};
Runnable task2 = () -> log.debug("task2 is running");//lambda
Thread t2 = new Thread(task1);
Thread t3 = new Thread(task2,"Third Thread");
t2.setName("Second Thread");
t1.start();
t2.start();
t3.start();
log.debug("main is running");
}
}
执行结果:
16:28:47.179 [main] DEBUG c.ThreadTest1 - main is running
16:28:47.179 [Second Thread] DEBUG c.ThreadTest1 - t2 is running
16:28:47.179 [Third Thread] DEBUG c.ThreadTest1 - task2 is running
16:28:47.179 [First Thread] DEBUG c.ThreadTest1 - t1 is running
Process finished with exit code 0
查看Runnable源码,我们可以发现,Runnable接口中只有一个抽象方法run(),@FunctionalInterface注解表明的方法都可以使用lambda表达式进行简化
@FunctionalInterface//只有一个抽象方法的情况下使用
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
在JVM虚拟机中,每一个线程都会对应一个栈,每一个线程的栈空间都是相互独立的,线程的一个方法对应栈中的一个栈帧。
JVM的内存结构:
- 程序计数器
程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。每个线程都有一个独立的程序计数器,它的作用是记录当前线程执行的位置,以便在发生线程切换时恢复执行位置。
- Java虚拟机栈
Java虚拟机栈是线程私有的,它的生命周期与线程相同。每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。当方法执行完毕后,对应的栈帧会被弹出,局部变量表等信息也会被销毁。
- 本地方法栈
本地方法栈与Java虚拟机栈类似,不同的是它为本地方法服务。本地方法是指使用其他语言(如C、C++)编写的方法,它们不会像Java方法那样被编译成字节码,而是直接被编译成机器码。本地方法栈的作用是为本地方法提供内存空间。
- Java堆
Java堆是Java虚拟机所管理的内存中最大的一块,它是被所有线程共享的一块内存区域。Java堆的作用是存放对象实例,几乎所有的对象实例都在这里分配内存。Java堆是垃圾收集器管理的主要区域,因此也被称为GC堆。
- 方法区
方法区也是被所有线程共享的一块内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。方法区也被称为永久代,但在JDK8之后,永久代被移除,取而代之的是元空间。
start()和run()
直接调用 t1.run():14:53:20.755 [main] DEBUG c.ThreadTest1 - t1 is running,可以很清晰的看到,这是main()主线程在执行方法,并不能起到多线程并发的作用,调用t1.start():14:53:20.755 [First Thread] DEBUG c.ThreadTest1 - t1 is running,可以看到,这才是t1线程启动执行方法
Java线程的优先级
在Java中,我们可以手动的调整线程的优先级,但是,具体的优先级执行情况还是由操作系统决定,Java中手动调整的优先级仅供参考,通过Thread的setPriority()方法可以调整线程的优先级,Java中线程的优先级从1-10,默认为5:
/**
* The minimum priority that a thread can have.
*/
public static final int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public static final int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public static final int MAX_PRIORITY = 10;
查看setPriority()源码:
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}

浙公网安备 33010602011771号