目录
线程概述
程序、进程、线程
程序:为了完成特定的任务或者功能,用计算机语言编写的一组指令集合,是一段静态的代码
进程:正在运行的程序,程序被加载到内存中,进程是操作系统中资源分配的最小单位
线程:进程可以进一步分为线程,是进程中最小的执行单元(任务),也是操作系统中进行任务调度的最小单位
在电脑硬件中,程序存放在硬盘中,进程在内存中运行,一个进程内细分了许多的线程任务,CPU处理的是内存中的线程任务
进程与线程的关系
一个线程只能属于一个进程,线程不能脱离进程
一个进程中至少有一个线程(主线程),java中的mian方法就是用来启动程序的主线程
一个进程内的所有线程共享该进程的内存资源
主线程中可以创建其他线程
java中创建线程
java中支持多线程,提供位于java.lang包下的Thread类来对线程进程管理,继承之后可以重写run()方法将线程中的任务写进去
两种方式:
1.通过继承Thread类来创建一个线程类
继承Thread类要重写run()方法,Thread类中的run()方法是不提供任何操作的,重写了run()方法之后,当 线程启动之后,会执行run()方法中的内容
public class MyThread extends Thread {
@Override
public void run() {
//super.run();由于Thread类的中的run()方法不是抽象方法,故重写时会默认调用Thread类中的run()方法
for (int i = 0; i < 1000; i++) {
System.out.println("MyThread"+i);
}
}
}
//测试代码
public static void main(String[] args) {
System.out.println("main线程开始了");
MyThread myThread=new MyThread();
myThread.start();//start()方法启动线程,启动后会自动调用执行run()方法的中线程任务
for (int i = 0; i < 1000; i++) {
System.out.println("main"+i);
}//由于现在的CPU功能比较强大,大多是4核或者8核的CPU,故CPU在工作的时候可以同时处理多个线程,线程创建之后就在内存中等待CPU调度
}
2.通过实现Runnable接口,并重写run()方法来创建一个线程任务类
Runnable接口中只有一个抽象方法public void run(),通过实现Runnable接口必须重写run方法,再利用 线程去调用该类,就可以在启动线程对象的时候执行run()方法中的内容
public class PrintNum implements Runnable {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
//Thread类中的静态native方法currentThread()获取当前调度的线程
}
}
}
//测试代码
public static void main(String[] args) {
System.out.println("main开始了");
//创建线程任务类的对象
PrintNum printNum=new PrintNum();
//创建线程对象,并将线程任务类的对象传入
Thread thread1=new Thread(printNum);
thread1.start();
Thread thread2=new Thread(printNum);
thread2.start();
}
两种方式的区别与联系: 【区别】 继承Thread: 线程代码存放Thread子类run方法中。 实现Runnable:线程代码存在接口的子类的run方法。 【实现Runnable的好处】 1)避免了单继承的局限性,可以继承其他父类 2)多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资源。
Tread类中的常用方法
run(),线程任务执行的方法
start(),启动线程
构造方法:
Thread()Thread(target),指定线程任务
Thread(target,name),指定线程任务,与线程名
static currentThread(),获取当前正在执行的线程
setName()/getName() 设置/获取线程名
线程优先级方法:
setPriority()设置线程的优先级
getPriority()获取线程的优先级
线程状态方法:
static sleep(millis),线程休眠指定的时间
static yield(),线程让出当前处理的CPU,并添加到就绪队列中
join(),等待该线程终止
public static void main(String[] args) throws InterruptedException {
//为测试方便直接抛出异常
System.out.println(Thread.currentThread().getName());//获取当前调用的线程
//创建线程任务类的对象
PrintNum printNum=new PrintNum();
Thread thread1=new Thread(printNum,"线程1");
//thread1.setPriority(10);//设置线程的优先级,线程默认优先级是5,范围在1-10,超出范围会报错
//线程优先级高的CPU会优先执行,但是不一定会每次都优先执行,具体看操作系统调度
thread1.start();
thread1.join();//等待线程终止后再执行后面的代码
Thread thread2=new Thread(printNum,"线程2");
//thread2.setPriority(1);
thread2.start();
}
}
//使用实现接口的方式创建线程
public class PrintNum implements Runnable {
@Override
public void run() {
//System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority());
//获取线程的优先级用于测试
for (int i = 0; i < 1000; i++) {
/* try {
Thread.sleep(1000);//线程休眠指定的时间
} catch (InterruptedException e) {
e.printStackTrace();
}*/
/* if (i%10==0){
Thread.yield();//线程让步
}*/
System.out.println(Thread.currentThread().getName()+":"+i);
//Thread类中的静态native方法currentThread()获取当前调度的线程
}
}
}
线程优先级
计算机只有一个CPU,线程在执行的过程中是轮流活动CPU的执行权的
操作系统中为线程设置了一个优先级别的机制,优先级较高的线程,获取CPU执行权的机会更多,而低则更少
优先级用整数表示,取值范围是1~10,一般情况下,线程的默认优先级都是5,可以通过setPriority()和getPriority()方法来设置或返回优先级;
Thread类中表示优先级的三个静态常量:
MAX_PRIORITY:取值为10,表示最高优先级。 MIN_PRIORITY:取值为1,表示最底优先级。 NORM_PRIORITY:取值为5,表示默认的优先级。
Java中线程的调度方法
● 同优先级线程组成先进先出队列,使用时间片策略 ● 对高优先级,使用优先调度的抢占式策略
线程状态
新建:当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态 就绪:处于新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件,只是没分配到CPU资源 运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run()方法定义了线程的操作和功能 阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出CPU并临时中止自己的执行,进入阻塞状态 死亡:线程完成了它的全部工作或线程被提前强制性地中止或出现异常导致结束
一个线程在它的声明周期中会经过上面五个状态
守护线程
任何一个守护线程都是整个JVM中所有非守护线程的保姆,只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作,当最后一个非守护线程结束工作的时候,守护线程随着JVM一同结束工作
守护线程的经典应用,例如垃圾回收站GC
用户线程和守护线程两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果用户线程已经全部退出运行了,只剩下守护线程存在了,虚拟机也就退出了。 因为没有了被守护者,守护线程也就没有工作可做了,也就没有继续运行程序的必要了.
设置守护线程: setDaemon(boolean on) 注意:设置线程为守护线程必须在启动线程之前,否则会抛出一个IllegalThreadStateException异常。
public class DaemonThread extends Thread {
//守护线程
@Override
public void run() {
while(true){
System.out.println("守护线程,默默守护用户线程");
}}}
public class MyThread extends Thread {
//主线程
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(i);
}}}
//测试代码
public static void main(String[] args) {
MyThread myThread=new MyThread();
myThread.start();
//守护线程,当用户线程停止时守护线程会一起停止
DaemonThread daemonThread=new DaemonThread();
daemonThread.setDaemon(true);//设置守护线程,必须在线程进入就绪状态前设置
daemonThread.start();
}