目录
a.继承Thread类,覆写run方法(现成的核心工作任务方法)
BLOCKED , WAITING , TIMED_WAITING
进程和线程
进程:程序在系统中的一次执行过程
进程是现在操作系统中资源分配(CPU,内存等关键系统信息)的最小单位,不同进程之间是相互独立的。
任务管理器中的进程就是这个
线程:进程中的一个子任务
线程是进程中的一个独立任务,比如浏览器进程的下载,听音乐等,就是浏览器进程的一些线程
同一个进程的所有线程共享该进程资源,线程是操作系统任务执行(系统调度)的基本单位
进程和线程的区别
1.进程是os资源分配的基本单位,线程是os系统调度的基本单位。
2.创建和销毁进程的开销要比线程大得多(开销相当于时间),线程更加轻量化。
3.调度一个线程也比调度一个进程快得多。(启动浏览器/浏览器标签,肯定是标签快)
4.进程包含线程,每一个进程至少包含一个线程(主线程)。
5.进程之间彼此相对独立,不同的进程不会共享内存空间,同一个进程的线程共享内存空间。
描述线程对象的类-Thread类
我们程序的入口是main方法,所有的调用都是从主方法开始的,所以相同的,所有的线程任务也是从主方法(主线程)开始进行。
Java中描述线程的类是Thread类——java.lang.Thread类线程的核心类,都是通过Thread类来启动一个线程。
当我们覆写完线程子类的run方法,在主方法中调用 线程对象.start方法来启动线程。
所有线程之间是并行关系,同时在电脑中执行
使用jconsole可以观察线程状态,用于对比各线程
run方法和start方法的区别
run方法
run方法是线程类的工作任务,也就是说,run方法决定了线程启动后要干什么,当run方法执行完毕(JVM启动run方法),线程会进入销毁状态。
start方法
start方法是Thread类中启动线程的方法,只有线程对象调用start方法时才会被系统调度,进入运行状态。
创建线程:Java中创建一个线程一共有四种方式
a.继承Thread类,覆写run方法(现成的核心工作任务方法)
//继承Thread类
public static class Run2 extends Thread{
@Override
public void run() {
System.out.println("继承Thread类");
}
}
ps:通过Thread类的start启动线程
a方式下的线程与启动
1.一个子类继承Thread类
2.覆写run方法
3.产生当前这个子类对象,而后调用start方法启动线程
使用匿名内部类创建Tread对象写法
//继承内部类创建Thread对象
Thread thread3 = new Thread() {
@Override
public void run() {
System.out.println("继承匿名内部类的Thread对象");
}
};
b.覆写Runnable接口,覆写run方法
public static class Run implements Runnable{
@Override
public void run() {
System.out.println("实现Runnable接口");
}
}
ps:通过Thread类的start启动线程
b方式下的线程与启动
1.实现Runnable接口
2.覆写run方法
3.创建Thread类的对象,调用start方法
使用匿名内部类实现Runnable接口
//继承匿名内部类的Runnable
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("继承匿名内部类的Runnable");
}
},"小鹏");
使用Lambda表达式
Thread thread3 = new Thread(()-> {
System.out.println("Lambda表达式的线程创建");
},"阿铭");
c.覆写Callable接口,覆写call方法
d.使用线程池创建线程
Thread类常见方法
Thread类就是JVM描述管理线程的类,每个线程都对应唯一的Thread对象
1.构造方法
如,传入Runnable接口类的方法都是构造方法
ps:可以在传入接口后给线程命名
2.Thread类的核心属性
一图流
3.启动线程调用的是Tread类的start方法
4.中断线程
中断线程的两种方式
a.通过共享变量进行中断
b.通过Thread.interrupted()静态方法或者Thread对象的成员方法isInterrupted()
Thread类中存在一个线程是否中断的属性
线程收到内置的中断通知的两种方式
a.当线程调用sleep/wait/join等方法处在阻塞状态时,收到中断通知thread.interrupt()
抛出中断异常 InterruptedException
当抛出异常后,当前线程的中断状态就会清除
b.线程没有调用以上三种方法,处在正常运行状态时收到中断通知thread.interrupt()
Thread.interrupted()判断当前线程是否被中断,若中断状态为true 清楚中断标志
Thread.currentThread.isInterrupted(); 判断指定线程对象是否状态为中断状态,若状态为true,不会清除中断标志
5.等待另一个线程-join方法
采用join方法,当一个线程中调用了另一个线程的join方法,那么要等调用线程执行完毕,才能继续执行此线程的后续代码。
join方法的变种
6.获取当前正在执行的线程对象
Thread.currentThread() => 获取正在执行的线程对象
例如
Thread.currentThread().getName()
Thread.currentThread().isInterrupted()
7.休眠当前进程
Thread.sleep(long millis) (ms)方法,在哪个线程中使用就休眠哪个进程。
8.将线程状态从运行态转换为就绪态 =>yield()方法
调用yield方法的线程会主动让出CPU资源,从运行态转为就绪态,等待被CPU继续调度。
到底啥时候让出CPU,又是啥时候被CPU再次调度,都是os调度的,我们无权选择。
此方法有两种可能性:
a.线程让出运行态之后,马上又调度
b.线程让出运行态之后,很久都不调度
此方法完全由CPU控制,我们不可控,所以使用不多。
线程的状态
附上一张状态图,下文叙述会依托下面此图
NEW
新建线程对象,new一个Thread对象就是new状态
新建状态,还没开始执行
RUNNABLE
就绪和运行,线程对象.start就是RUNNABLE状态
下一个状态,可执行状态(真正在运行和即将开始执行,都是这个状态)
BLOCKED , WAITING , TIMED_WAITING
等待状态,三种等待状态均为阻塞状态(该线程需要暂缓执行,这三个造成的暂缓执行原因不同)
TIMED_WAITING
超时等待,表示该线程需要等待一段时间后再恢复执行
例如sleep方法就是此种等待方式
BLOCKED
当线程被锁住等待获取锁对象就是BLOCKER状态
WAITING
当线程使用lock.wait()方法时,说明进入线程等待状态,需要另一个线程的lock.notify方法解锁此线程
TERMINATED
run方法执行完毕,或者抛出异常不正常执行完毕
终止状态,表示当前线程已经执行结束了,可以销毁了
可以用主线程的线程对象.isAlive()方法判断线程是否存活