目录
进程和线程
并发和并行
继承实现Runnable接口的Thread类实现的多线程
实现Runnable接口创建线程类
线程常用方法
进程和线程
进程:一个程序的启动就可以抽象化为一个进程
线程:线程是由进程开启的,一个进程可以创建多个线程,多个线程同时运行
并发和并行
并发:同一时刻,多个任务交替执行。简单说,单核CPU执行多任务就是并发。
并行:同一时刻,多个CPU可以实现多个任务,可以实现并行。
并发和并行的比较:
继承实现Runnable接口的Thread类实现的多线程
- 一个类继承Thread线程类,该类就可以当作线程类使用
- 在继承Thread类的类中,需要重写Runnable下的run方法,在该方法的内部实现自己的业务逻辑
- run方法会在调用start方法时由JVM隐式调用
- 多个线程之间的逻辑会交替执行,当所有的线程逻辑执行结束后,进程才结束
继承Thread类的Fun类的功能的实现:
public class ThreadTestDrive { public static void main(String[] args) throws InterruptedException { Fun fun = new Fun(); fun.start(); //调用start方法隐式调用run方法 for (int j = 1; j <= 40; j++) { System.out.println("j" + " " + j + "---" + Thread.currentThread().getName()); Thread.sleep(1000); } } } class Fun extends Thread { @Override public void run() { //覆写run方法 for (int i = 1; i <= 60; i++) { System.out.println("i" + " " + i + "---" + Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
线程逻辑/多线程机制:
为什么是start而不是run?
不妨直接调用下run方法,会发现程序总是在执行完run方法中的逻辑后才继续向下执行,在这里起始没有新线程的产生,而只是单纯的调用了fun对象的run方法:
再来看下start方法的源码:
会发现调用start方法的本质是调用了start0底层方法,start0方法由JVM调用操作特定类型操作系统中的函数完成新线程的启动,可以理解为start调用了start0方法,start0方法在底层开启新线程执行了run方法中的逻辑。值得注意的是,每一种操作系统都有自己特定的一套算法响应start0方法的逻辑。
实现Runnable接口创建线程类
有了Thread类,为什么还要有Runnable接口?
为了解决Java的单继承缺陷。如果一个类继承了除Thread类外的另一个类,那么该类就无法在继承Thread类,也就无法创建新的线程。使用Runnable接口可以解决这个问题。同时Runnable接口实现的线程类更适合于多线程共享资源的情况(t3):
实现Runnable接口创建线程类Fun:
public class RunnableTestDrive { public static void main(String[] args) throws InterruptedException { Fun fun = new Fun();//实现了Runnable接口的Fun类的实例化对象 //静态代理 Thread thread = new Thread(fun); thread.start(); for(int i=1;i<=40;i++) { System.out.println(i + "===" + Thread.currentThread().getName()); Thread.sleep(1000); } } } class Fun implements Runnable { @Override public void run() { for (int i = 1; i <= 40; i++) { System.out.println(i + "---" + Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
Runnable创建线程的逻辑:
模拟Thread类的静态代理作用:
class ThreadSimulate { private Runnable target; public ThreadSimulate(Runnable target) { this.target = target; } public void start() { start0(); } public void start0() { run(); } public void run() { if(target != null) { target.run(); } } }
线程常用方法
- 线程退出
线程退出有两种方式,run方法执行结束后退出和在外接控制变量的方式结束run方法的执行:public class RunMethodToSucceed implements Runnable { private boolean loop = true;//控制run方法中循环的变量 @Override public void run() { while(loop) { System.out.println(Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public void setLoop(boolean loop) { this.loop = loop; } }
线程中断
public void isInterrupted()判断线程是否中断
public void interrupt()中断线程的执行(提前结束线程的休眠)线程礼让
是指将当前CPU的调度资源让给其他线程使用,当前线程等待下次调用,当CPU资源充足时,礼让可能不会起作用。
public static void field()线程强制执行
public void join()将当前线程的执行进程加入到线程队列的最前面,并且等到该线程执行结束后才去执行其他的线程。设置/获取线程优先级
CPU会根据线程的优先级优先调度,那个线程的优先级高,最有可能先被调度。
public static final int MIN_PRIORITY = 1;
public static final int NORM_PRIORITY = 5;
public static final int MAX_PRIORITY = 10;
pulbic void setPriority()设置线程的优先级
public void getPriority()获取线程的优先级线程睡眠
pulbic static void sleep()设置守护线程
用户/工作线程和守护线程:
用户/工作线程:执行完任务退出或者接收到通知退出。
守护线程:一般为工作线程服务,当所有的用户线程结束,工作线程结束,常见的守护线程有垃圾回收机制
线程的七大状态
创建状态new:在new Thread之后,没有start之前,线程都属于创建状态。
运行状态Runnable:运行状态又分为就绪ready和运行running状态,这两种状态取决于CPU的调度。
阻塞状态Blocked。
等待状态waitting:等待另一个线程执行特定特定动作的线程处于此状态。
超时等待状态timed waitting:等待另一个线程执行指定动作达到指定时间的线程的状态。
终止状态terminated:线程的run方法执行结束后处于的状态