多线程
1.认识线程
1.1概念
- 进程是系统分配资源的最小单位
- 线程是系统调度的最小单位
- 一个进程内的线程之间是可以共享资源的
- 每个进程内至少有一个线程存在,即主线程
进程和线程的区别?
1.进程是系统分配资源的最小单位
2.线程是系统调度的最小单位
3.一个进程中的各个线程之间共享 方法区(常量池)、堆
线程也存在并发、并行
代码1:
public static void main(String[] args) throws InterruptedException {
Thread.sleep(9999999L);
}
使用jconsole命令观察线程
代码2:
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(9999999L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
使用jconsole命令观察线程
代码1的线程名字是 main ,而代码2的线程名字是 Thread-0
原因如下:
Java 程序启动的流程:
把 java 文件名作为参数 传给 java
java.exe 启动
(1) 调用系统api分配进程的资源
(2) 调用系统级别C语言main方法(启动一个主线程,系统级别)每个进程至少有一个线程存在,即主线程
(3) 启动主线程后,调用initialize_JVM:初始化 java 虚拟机参数
create_VM:根据初始化参数创建 java 虚拟机
启动 jvm 内部的守护线程(后台线程):如垃圾回收线程等等
调用 java 代码中 main 方法(启动Java main 方法)
java 级别的 main 方法可以退出
Java级别的线程创建 本质上 还是要 调用操作系统级别的线程创建 系统级别的创建 是非常耗时的
多线程的优势:增加运行速度
public class Test {
//线程并不一定就能提高速度,可以观察,COUNT、NUM不同,运行效果也不同
private static final int COUNT = 10_0000_0000;
private static final int NUM = 2;
public static void sum() {
int b = 0;
for (int i = 0; i < COUNT; i++) {
b--;
}
}
public static void concurrency() {
//并发
long start = System.nanoTime();
for (int i = 0; i <NUM ; i++) {
new Thread(new Runnable() {
@Override
public void run() {
sum();
}
}).start();
}
//等待当前线程结束
while (Thread.activeCount()>1) {
Thread.yield();// 将当前线程由 运行态-->就绪态
}
long end = System.nanoTime();
System.out.printf("并发执行的时间为%d毫秒\n",end-start);
}
public static void serial() {
//串行
long start = System.nanoTime();
for (int i = 0; i <NUM ; i++) {
sum();
}
long end = System.nanoTime();
System.out.printf("串行执行的时间为%d毫秒\n",end-start);
}
public static void main(String[] args) {
//使用并发方式
concurrency();
//使用串行方式
serial();
}
}

1.2 创建线程
方法1:继承 Thread 类
class MyThread extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
public class Test2 {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
方法2:实现 Runnable 接口
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
Thread t = new Thread(new MyRunnable());
t.start(); //线程开始运行
方法3:匿名类创建 Thread 子类对象
Thread t = new Thread() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
};
方法4:匿名类创建Runnable 子类对象
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
2.Thread 类及常见方法
2.1 构造方法
创建线程:
Thread()
使用Runnable对象创建线程对象
Thread(Runnable target)
创建线程对象,并命名
Thread(String name)
使用Runnable对象创建线程对象 并命名
Thread(Runnable target,String name)
2.2 属性

- ID 是线程的唯一标识,不同线程不会重复
- 优先级更高的线程,更有可能先执行,但不是一定,只是几率大
- JVM会在一个进程的所有非后台线程结束后,才会结束运行
- 是否存活就是 run() 方法是否运行结束了
2.3 线程的run()和start()
class MyThread extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
public class Test2 {
public static void main(String[] args) {
MyThread myThread = new MyThread();
//run()直接调用,不会启动线程
//只是在当前的 main 线程中调用run()方法
myThread.run();
//调用 start() 方法是启动了线程
//myThread.start();
}
}
2.4 守护线程
守护线程的运行条件:
- 至少有一个非守护线程,进程不会退出
非守护线程一般称为 工作线程
守护线程一般称为 后台线程
设置为守护线程
setDaemon(true)
2.5 常用方法
将当前进程由运行态---->就绪态 线程的让步
//等待当前线程结束
while (Thread.activeCount()>1) {
Thread.yield();// 将当前线程由 运行态-->就绪态
}
将当前进程由运行态---->阻塞态 等待(当前进程自行运行)
join()
join(long millon)
无参数:等待当前线程执行完毕
有参数:
- 和时间参数相比
- 如果时间参数比线程运行时间长,那就让当前线程执行完毕
- 如果时间参数比线程运行时间短,那就执行下面的线程
activeCount()和yield() 组合可以实现 join() 等待线程
来源:CSDN
作者:刘思雨579
链接:https://blog.csdn.net/weixin_45608849/article/details/104736115