*线程创建的方式:
1.继承Thread类,重写run方法。
2.实现Runnable接口,重写run方法。
实际这两个run方法都重写的是Runnable中的run方法
简化方法:
1.匿名内部类创建Thread 子类对象
Thread thread = new Thread(){@Overridepublic void run() {while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("hello Thread...");}}};
模板:
Thread thread = new Thread(){
run( )
};
2.匿名内部类创建Runnable子类,实现Runnable接口,并重写run方法
Thread thread1 = new Thread(new Runnable() {@Overridepublic void run() {while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("hello Runnable...");}}});
模板:
Thread thread1 = new Thread(new Runnable() {
run()
});
3.lambda表达式创建
Thread thread2 = new Thread(() -> {while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("hello lambda...");}});
模板:
Thread thread2 = new Thread(() -> {
语句
});
*多线程的实现
假如有一个任务,分别让一个人单独完成,和二个人同时完成。显然是二个人较快。
多线程也是如此。
例如:
public static void main(String[] args) {Thread thread1 = new Thread(() -> {while (true) {System.out.println("工作任务-5...");}});Thread thread2 = new Thread(() -> {while (true) {System.out.println("工作任务-5...");}});//多线程thread1.start();thread2.start();}
当任务较大时,多线程可以节省将近一半时间。
当任务较少时,不建议使用多线程,这会造成系统资源浪费。
* 线程类及其常见方法
1.常见构造方法
在后台查看线程时,如果每个线程都有自己的名字,那么出错时就会很快找到。
Thread()创建线程对象
Thread(Runnable target)使用Runnable对象创建线程
Thread(String name)创建线程对象,并命名
Thread(Runnable target , String name)使用Runnable对象创建线程,并命名
public class Thread_name {public static void main(String[] args) {Thread thread4 = new Thread(() ->{while (true) {System.out.println("我有名字:" + Thread.currentThread().getName());}},"Thread");thread4.start();}
}
注: Thread.currentThread()用于线程内调用线程对象
2. Thread的几个常见属性
属性 | 获取方法 |
ID | getId() |
名称 | getName() |
状态 | getState() |
优先级 | getPriority() |
是否后台线程 | isDaemon() |
是否存活 | isAlive() |
是否被中断 | isInterrupted() |
这个ID是JVM默认为Thread对象生成的编号,属于Java层面,要和PCB区分开,PCB是操作系统层面的
也是JAVA层面的
我们看一看有哪些状态:
NEW:表示创建好了一个Java线程对象,安排好了任务,处于准备就绪状态。
但是还没有启动没有调用start()方法之前是不会创建PCB的,和PCB没有任何关系
RUNNABLE:正在运行+准备就绪状态,最常见的状态
有系统PCB
BLOCKED:等待锁的状态,阻塞的一种。(因为 锁竞争 引起的阻塞)
WAITING :没有等待时间,一直死等,直到被唤醒。
TIMED_WAITING:指定了等待时间的阻塞状态,过时不侯
TERMINATED:结束,完成状态,PCB已经销毁,但是JAVA线程对象还在
线程已经结束,Thread对象还存在
创建线程时默认是前台线程
前台线程可以阻止进程的退出
后台线程不阻止进程的退出
设置成后台线程之后,main方法执行完成之后整个程序就退出了,子线程也就自动结束了
如果是前台线程子线程不会受main方法的影响会一直运行下去
描述的是PCB的状态,可以查看run()方法是否执行完成
public static void main(String[] args) {Thread thread = new Thread(() -> {System.out.println("我的名字:" + Thread.currentThread().getName());});System.out.println(thread.getName() + "Id:" + thread.getId());System.out.println(thread.getName() + "状态:" + thread.getState());System.out.println(thread.getName() + "优先级:" + thread.getPriority());System.out.println(thread.getName() + "后台线程:" + thread.isDaemon());System.out.println(thread.getName() + "活着:" + thread.isAlive());System.out.println(thread.getName() + "被中断:" + thread.isInterrupted());thread.start();//执行后System.out.println(thread.getName() + "后台线程:" + thread.isDaemon());System.out.println(thread.getName() + "活着:" + thread.isAlive());System.out.println(thread.getName() + "被中断:" + thread.isInterrupted());}
3.启动一个线程start()
在没有启动线程之前,复写run()方法是发布要执行的任务,创建线程实例是把做任务的人叫了过来,到还没真正开始做任务,只有调用start()方法,这个“线程"才会去执行任务。
4.终止一个线程
1.使用interrupt ()方法,终止一个线程
public static void main(String[] args) {Thread th = new Thread(() -> {while(true) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("我在执行...");}});th.start();try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("快终止线程!!");th.interrupt();}
如果程序正常执行他在打印五个执行之后就会被终止但是实际运行却报了异常。
这是因为线程终止时,中止的是sleep方法
这个时候我们就需要在sleep方法中进行逻辑处理,使其达到目标,也就是终止程序
2.自定义一个标志位用于通知线程中断
lambda里面如果使用局部变量
触发“变量捕获”
需要把这个变量定义为全部的
全局静态变量
5.等待一个线程join
有时候我们需要等待一个线程结束后才开始另一个线程,例如:准备好原材料后才能开始制作产品。这时我们就需要join()方法
方法 | 说明 |
public void join() | 等待线程结束 |
public void join(long millis) | 等待线程结束,最多等millis毫秒 |
public void join(long millis, int nanos) | 同理,但精度更高 |
6.获取当前线程的引用
方法 | 说明 |
public static Thread currentThread() | 获取当前对象的引用 |
使用在Thread内部,调用自身