多线程基础知识
1.进程与线程
进程:在内存中执行的应用程序
线程:进程中的一个最小的执行单元
2.并发与并行
并行:在同一时刻,有多个指令在多个CPU上同时执行
并行:在同一时刻,有多个指令在单个CPU上交替执行
3.CPU调度
分时调度
抢占式调度(java程序)
4.主线程
CPU和内存之间开辟的为main方法服务的线程
创建多线程方式⭐⭐⭐⭐⭐
1 继承Thread
- 定义一个类,继承Thread
- 重写run方法,设置线程任务
- 创建自定义线程对象
- 调用start方法,jvm自动执行run方法
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("MyThread...执行了"+i);
}
}
}
public class Test01 {
public static void main(String[] args) {
//创建线程对象
MyThread t1 = new MyThread();
//调用start方法,开启线程,jvm自动调用run方法
t1.start();
for (int i = 0; i < 10; i++) {
System.out.println("main线程..........执行了"+i);
}
}
}
实现Runnable
- 定义一个类,实现Runnable接口
- 重写run方法,设置线程任务
- 创建自定义线程类,将其放到Thread对象中
- 调用start方法,开启线程,jvm自动执行run方法
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"...执行了"+i);
}
}
}
public class Test01 {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread t1 = new Thread(myRunnable);
//调用Thread中的start方法,开启线程
t1.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"...执行了"+i);
}
}
}
3.匿名内部类(属于实现Runnable接口的一种)
new Thread(new Runnable(){
重写run方法;
}.start();
Thread中的方法
⭐void start()
-> 开启线程,jvm自动调用run方法
⭐void run()
-> 设置线程任务,这个run方法是Thread重写的接口Runnable中的run方法
String getName()
-> 获取线程名字
void setName(String name)
-> 给线程设置名字
⭐static Thread currentThread()
-> 获取正在执行的线程对象(此方法在哪个线程中使用,获取的就是哪个线程对象)
⭐static void sleep(long millis)
->线程睡眠,超时后自动醒来继续执行,传递的是毫秒值
void setPriority(int newPriority)
-> 设置线程优先级,优先级越高的线程,抢到CPU使用权的几率越大,但是不是每次都先抢到
int getPriority()
-> 获取线程优先级
void setDaemon(boolean on)
-> 设置为守护线程,当非守护线程执行完毕,守护线程就要结束,但是守护线程也不是立马结束,当非守护线程结束之后,系统会告诉守护线程人家结束了,你也结束吧,在告知的过程中,守护线程会执行,只不过执行到半路就结束了
static void yield()
-> 礼让线程,让当前线程让出CPU使用权
void join()
-> 插入线程或者叫做插队线程
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//线程睡眠
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+"...执行了"+i);
}
}
}
public class Test01 {
public static void main(String[] args) throws InterruptedException {
//创建线程对象
MyThread t1 = new MyThread();
//给线程设置名字
t1.setName("金莲");
//调用start方法,开启线程,jvm自动调用run方法
t1.start();
for (int i = 0; i < 10; i++) {
Thread.sleep(1000L);
System.out.println(Thread.currentThread().getName()+"线程..........执行了"+i);
}
}
}
问题:为啥在重写的run方法中有异常只能try,不能throws
原因:继承的Thread中的run方法没有抛异常,所以在子类中重写完run方法之后就不能抛,只能try
线程安全
线程不安全
多个线程访问同一个资源,导致数据有问题
同步代码块⭐⭐⭐⭐⭐
synchronized(任意锁对象){
可能出现线程不安全的代码;
}
同步方法⭐⭐⭐⭐⭐
- 非静态的同步方法
修饰符 synchronized 返回值类型 方法名(形参){
方法体;
返回值;
}
默认锁 : this
2. 静态的同步方法
修饰符 static synchronized 返回值类型 方法名(形参){
方法体;
返回值;
}
默认锁 : class对象
线程状态
线程状态 | 导致状态发生的条件 |
---|---|
NEW(新建) | 线程刚被创建,但是并未启动。还没调用start方法。 |
Runnable(可运行) | 线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。 |
Blocked(锁阻塞) | 当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。 |
Waiting(无限等待) | 一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。 |
Timed Waiting(计时等待) | 同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、Object.wait。 |
Terminated(被终止) | 因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。或者调用过时方法stop() |