相关概念
- 进程
- 线程—单线程/多线程
- 并发—单核CPU实现多任务
- 并行—同一时刻,多个任务同时执行。多核CPU可以实现并行
一个程序启动时,即一个进程启动以后,会默认启动一个主线程(main),可以在主线程中创建子线程Thread1,Thread2,也可以在子线程中继续创建子线程,
主线程的生命周期和子线程不一定相同,可能主线程已经结束了,子线程还在继续执行。
同一个应用程序可以有多个进程,和多个线程
创建线程
创建线程的两种方式
a. 继承Threadclass A extends Thread{
@Override
public void run() {
//do something
}
}
}
b. 实现Runnable—由于Java中不支持多继承,如果一个类A已经继承了其他的类,如果A还想继续在里面实现多线程,则无法继承Thread来实现,这时候可以使用Runnable
class A extends B implements Runnable{
@Override
public void run() {
//do something
}
}
}
这两种方式本质上没有区别,都是走的start0()函数,Runnable更加适合多个线程共享一个资源的情况,避免单继承的限制
售票系统
线程退出(中断线程)
- 通知方式
public class ThreadExitDemo {
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
myThread.start();
//休眠10秒,通知线程退出
Thread.sleep(5000);
//通知线程退出
myThread.setLoop(false);
}
}
class MyThread extends Thread {
//提供方法用于外部来通知线程内部退出
public void setLoop(boolean loop) {
this.loop = loop;
}
//设置一个控制变量
private boolean loop = true;
@SneakyThrows
@Override
public void run() {
while (loop) {
Thread.sleep(50);
System.out.println("====");
}
}
}
- 线程常用方法
- setName
- getName
- start—底层调用run()方法,run方法本身不会创建线程,run()里面调用的start0()会开启线程,由CPU决定如何调度
- run
- setPriority
- getPriority
- interrupt—中断线程,没有正真结束线程,一般用于中断正在休眠的线程
- sleep
- yield—让出CPU供其他线程执行,不一定成功
- join—线程插队 在主线程中执行t.goin(),则表示先执行完子线程在回到主线程中继续执行
package com.example.usage;
import lombok.SneakyThrows;
/**
* @author chenzhian
* @description 线程常用方法示例
* @date 2021年05月07日 15:08
*/
public class ThreadMethodDemo {
public static void main(String[] args) throws InterruptedException {
// 调用对方的join方法
T t = new T();
t.start();
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
System.out.printf("[主线程] %s 正在做事 %d \n", Thread.currentThread().getName(), i);
// 主线程执行到第5个时,让出CPU资源,让子线程执行完我再继续执行
if (i == 5) {
System.out.println("干大事的先来...");
// 关键方法--这里让t执行完毕
t.join();
// Thread.yield();//不一定能让成功
System.out.println("现在又轮到主线程继续干事情了");
}
}
}
}
class T extends Thread {
@SneakyThrows
@Override
public void run() {
for (int i = 0; i < 20; i++) {
Thread.sleep(500);
System.out.printf("[子线程] %s 干了 %d 件大事 \n", Thread.currentThread().getName(), i);
}
}
}
守护线程
守护线程示例
package com.example.usage;
import lombok.SneakyThrows;
/**
* @author chenzhian
* @description 守护线程示例--主线程退出以后,守护线程自动结束
* @date 2021年05月07日 15:58
*/
public class DaemonThreadDemo {
public static void main(String[] args) throws InterruptedException {
MyDaemonThread myDaemonThread = new MyDaemonThread();
// [1] 设置为守护线程
myDaemonThread.setDaemon(true);
myDaemonThread.start();
for (int i = 0; i < 10; ++i) {
Thread.sleep(1000);
System.out.printf("宝宝玩了 %d 个小时了 \n", i);
}
}
}
class MyDaemonThread extends Thread {
@SneakyThrows
@Override
public void run() {
// 无限循环
for (; ; ) {
Thread.sleep(1000);
System.out.println("爸爸妈妈在看着孩子");
}
}
}
线程状态/生命周期
public class ThreadLifeScopeDemo {
public static void main(String[] args) throws InterruptedException {
T2 t = new T2();
System.out.printf("[%s] --> %s \n", t.getName(), t.getState());
t.start();
while (Thread.State.TERMINATED != t.getState()) {
System.out.printf("[%s] --> %s \n", t.getName(), t.getState());
Thread.sleep(500);
}
// 主线程休眠10秒,通知线程退出
Thread.sleep(5000);
// 通知线程退出
t.setLoop(false);
System.out.printf("[%s] --> %s \n", t.getName(), t.getState());
}
}
class T2 extends Thread {
// 设置一个控制变量
private boolean loop = true;
// 提供方法用于外部来通知线程内部退出
public void setLoop(boolean loop) {
this.loop = loop;
}
@SneakyThrows
@Override
public void run() {
while (true) {
for (int i = 0; i < 10; ++i) {
System.out.println("test Thread State");
Thread.sleep(500);
}
//for循环以后退出
break;
}
}
}
输出:
[Thread-0] --> NEW
[Thread-0] --> RUNNABLE
test Thread State
test Thread State
[Thread-0] --> RUNNABLE
test Thread State
[Thread-0] --> RUNNABLE
test Thread State
[Thread-0] --> RUNNABLE
test Thread State
[Thread-0] --> RUNNABLE
test Thread State
[Thread-0] --> RUNNABLE
test Thread State
[Thread-0] --> RUNNABLE
test Thread State
[Thread-0] --> RUNNABLE
test Thread State
[Thread-0] --> RUNNABLE
test Thread State
[Thread-0] --> RUNNABLE
[Thread-0] --> TERMINATED
Process finished with exit code 0
线程同步—Synchronized
当一个线程在对内存进行操作时,其他线程不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能够对该地址进行操作
互斥锁&死锁
- 线程死锁
- 释放锁