1.线程的定义
2.线程和进程的区别和应用
3.多线程的五种代码实现方式
1.使用继承Thread类,重写run方法实现
2.使用实现Runnable接口,重写run方法
3.继承Thread类,使用匿名内部类
4.实现Runnable,使用匿名内部类
5.使用lambda表达式
4.查看线程的方法
5.Thread类的常见方法
6.Thread类常见的几个属性
1.什么是线程
线程是独立的执行流,进程包含线程,多个线程在进程中也是并发执行的,多个线程在CPU上调度执行的顺序是随机的
在Java中我们会采用多线程编程,为啥不采用多进程编程呢
操作系统提供了多进程的API,但是JDK并没有对这些API进行进一步封装,所以Java无法使用
,那么就采用多线程编程
线程和进程相比更加轻量,创建线程耗费的资源也更少
一个进程的多个线程之间共用同一份资源
1.内存资源
2.文件描述符表
只有在进程启动,创建第一个线程的时候,需要申请系统资源,之后的线程就不用了,进程之间互不影响,但是线程之间一旦有一个崩溃了,那么就可能导致其他线程也崩溃,导致整个进程崩溃
这个可能比较抽象,我来举个例子
比如CCtalk,我们点击运行,它是一个进程,里面的声音,画面等功能就是多线程,假如画面卡顿了,就有可能导致声音卡顿,甚至导致整个程序崩溃
来解释一下多个线程是并发执行的原因
这里的并发说的也是并发+并行
可以在多个CPU的多个核心同时执行
可以在一个CPU的一个核心上,进行快速调度运行
可以在一个CPU的多个核心上同时进行
其实操作系统调度的是线程,我们所说的进程调度是因为之前讨论的是进程只有一个线程的情况
说了这么多,我们来总结一下的进程和线程的区别
1.进程包含线程
2.进程有独立的内存资源和文件描述符表,同一个进程的多个线程之间,共享同一份内存地址和文件描述符表
3.进程是操作系统资源分配的基本单位,线程是操作系统进程调度的基本单位
4.进程之间具有独立性,线程不具有独立性
5.创建线程比创建进程快
6.销毁线程比销毁进程快
7调度线程比调度进程快
下面来说一说线程的代码表现
线程其实是操作系统的概念,Java进一步对线程API进行封装,Java有个Thread类就是表示线程的,下面让我们用代码来看看
1.继承Thread类,重写run方法实现
package threading; //继承Thread类,重写run方法 class MyThread extends Thread{ @Override public void run() { System.out.println("hello t "); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } public class ThreadDemo1 { public static void main(String[] args) { Thread t = new MyThread();//向上转型 //创建一个新的线程 t.start(); t.run();//注意,这个方法代表还是主线程里面的 while (true) { System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
2.继承runnable接口,重写run方法
class MyRunnable implements Runnable{ @Override public void run() { while(true){ System.out.println("hello t"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } public class ThreadDemo2 { public static void main(String[] args) { MyRunnable runnable=new MyRunnable(); Thread t=new Thread(runnable); t.start(); while(true){ System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
3.继承Thread类,实现匿名内部类
public class ThreadDemo3 { public static void main(String[] args) { Thread t=new Thread(){ @Override public void run() { while(true){ System.out.println("hello t"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }; t.start(); while(true){ System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
4.继承runnable 接口,实现匿名内部类
public class ThreadDemo4 { public static void main(String[] args) { Thread t=new Thread(new Runnable() { @Override public void run() { while(true){ System.out.println("hello t"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }); t.start(); while(true){ System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
5.使用lambda表达式
public class ThreadDemo5 { public static void main(String[] args) { Thread t=new Thread(()->{ while(true){ System.out.println("hello t"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); t.start(); while(true){ System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
我们有时候需要查看线程的状态,这时需要使用idea下的一个工具,方法如下
1.运行线程
2.打开Java所在文件目录,找到bin目录下的jconsole.exe,点击运行
C:\Program Files\Java\jdk1.8.0_192\bin,在我的电脑是这个路径,每个人的应该是不一样的
线程在跑的时候,就可以通过这个工具看到
Thread常见的方法
Thread()//创建线程对象
Thread(Runnable target)//继承runnable接口,创建线程对象
Thread(String name)//给线程起个名字,方便调试
Thread(Runnable target ,String name)//使用 Runnable 对象创建线程对象,并命名
起名字这个只是起个名字,开举个例子
再次打开JDK下的jconsle查看
就是为了方便调试而已
Thread类的一些属性,线程有自己的状态,优先级,上下文,记账信息,id等,其实进程 的属性就是线程的,只是我们那个时候讨论的是只有一个线程的进程
ID getId()
名称 getName()
状态 getState()
优先级 getPriority()
是否后台线程 isDaemon()
是否存活 isAlive()
是否被中断 isInterrupted()
这一期就先聊前六个,中断放到下一期,这个比较复杂
先看id,每个线程都有自己的'id',这算自己的身份标识
name就是每个线程的名字了
状态,举个例子
现在的代码是runnable状态,也就是正在运行
对于优先级和状态后后期进行详细讲解
看看isDaemon()方法,结果默认是false,那就是后台线程,如果改为true,那就是前台线程.
上代码
public class ThreadDemo8 { public static void main(String[] args) { Thread t=new Thread(()->{ while(true){ } }); t.start(); //此时默认是前台线程,阻止线程结束 } }
一直在跑,但是没有结束
public class ThreadDemo8 { public static void main(String[] args) { Thread t=new Thread(()->{ while(true){ } }); t.setDaemon(true);//将值改为true,变为后台进程,不阻止线程结束 t.start(); //此时默认创建的线程是前台线程,阻止线程结束 } }
t.isAlive()方法,结果是啥取决于线程的入口方法是否执行结束,如果执行执行结束,结果就为false,否则为true
说了这么多,来总结一下吧
1.前台线程会阻止Java进程 的结束,Java进程中所有的前台线程结束以后进程才能结束
2.后台进程不会阻止Java进程的结束,不管后台进程结没结束,只要所有前台进程结束,进程就结束
3.线程对应的入口方法执行完,这个时候线程就不存在了
最后:来区分一下t.start和t.run()方法:
作用功能不同:
- run方法的作用是描述线程具体要执行的任务;
- start方法的作用是真正的去申请系统线程
运行结果不同:
- run方法是一个类中的普通方法,主动调用和调用普通方法一样,会顺序执行一次;
- start调用方法后, start方法内部会调用Java 本地方法(封装了对系统底层的调用)真正的启动线程,并执行run方法中的代码,run 方法执行完成后线程进入销毁阶段。
今天的分享就到这里,下期再见