- 线程的理解
- 一※、线程的创建【线程类】【任务类】【Callable】
- 方式一:通过继承Thread类实现 【线程类】
- 线程类的读取线程名常用方法
- 方式二:通过自定义类实现runnable接口,定义一个【可重复利用】的【任务类】 【方便线程间共享数据】【可以使用匿名内部类】
- 练习:【任务类】【匿名内部类】实现n的阶乘程序
- 【任务类】获取现在对象的名字和【currentThread】获取当前执行的线程对象
- 练习:火车票抢票【分别使用线程类和任务类来实现】
- 方式三:通过自定义类实现Callable接口,定义一个可返回数据、可以抛出异常的执行操作
- 三种创建方式有什么区别?分别在什么场景下应用?
- 二※、线程的生命周期
- 三※、线程的控制
- 1、睡眠sleep:
- 合并:让当前线程进入阻塞状态,直到调用join方法的线程完成之后,再回到当前线程进行操作
- 线程合并案例1,一个和尚去挑水,另一个和尚负责下水烧饭【要挑水完成,再下水烧饭】
- 线程合并案例2,一个和尚去挑水,另一个和尚负责下水烧饭【等待一段时间,没有等到先去扫地】
- 实现1
- 实现2
- 2、让步yield:使得当前线程让出cpu,再回到就绪状态,和其他线程一起再去抢夺资源
- 线程优先级:1-10【值越高,优先级越高,能获得更多的执行机会 】
- 3、挂起suspend、唤醒resume:【理解即可】
- 4、中断interrput:【理解即可】
- 5、停止:调用stop()会结束线程和终止线程的生命周期
- 停止线程stop()
- 终止线程的生命周期
Java中的多线程:通过多并发来实现提高运行速率
–线程和进程的理解
–程序:由开发人员编写代码程序,是“死的”
–进程:由多个线程组成的,是“活的”,运行状态
–线程:接收信息的线程、发送信息的线程
由于cpu的处理能力非常强大,在人的视觉、感官来说,是觉得在同一时间上运行的(cpu会不定时让出时间片,给线程进行强占,不断的切换线程,执行不同的任务)
进程之间能不能共享同一个内存空间?不能的,每个进程都有他独自的内存空间
实现数据共享是在线程之间实现的
–独立性
–动态性
–并发性
简单,方便使用、容易获取线程的信息
构造方法: public Thread():分配一个新的线程对象。 public Thread(String name):分配一个指定名字的新的线程对象。 public Thread(Runnable target):分配一个带有指定目标新的线程对象。 public Thread(Runnable target,String name):分配一个带有指定目标新的线程对象并指定名字。 常用方法: public String getName():获取当前线程名称。 public void start():导致此线程开始执行; Java虚拟机调用此线程的run方法。 public void run():此线程要执行的任务在此处定义代码。 public static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。 public static Thread currentThread():返回对当前正在执行的线程对象的引用。
package com.daily022;
// 自定义的一个线程类,执行任务 【Thread】是Java中的线程类
// 第一种方式通过继承Thread实现线程类的定义
public class MyThread extends Thread {
// 线程在Java中默认的工作工作方式是抢占式 【抢夺资源】而不是调用资源
// 测试方法
public static void main(String[] args) {
// 1、创建线程对象进行
MyThread t1 = new MyThread();
// 2、应该先启动线程。线程去抢夺cpu,然后再执行任务
// t1.run();// 这个是错误的启动线程的方法,这个只是调用实例化对象的方法
// 012345678910
// 正确的启动方法是;
// 开启线程【走完生命周期】
t1.start();//012345678910
}
// 1、在Thread中找到下面源码
// class Thread implements Runnable {
// 2、然后再打开Runnable方法 再查找run方法
// public abstract void run();
// 才发现最下面有一个run方法
// 线程所要执行的任务
@Override
public void run() {
// 实现1~10的打印输出操作
for (int i = 0; i <= 10; i++) {
System.out.print(i);
}
}
// 普通方法
// 可以理解为类里的方法
public void run2() {
// 实现1~10的打印输出操作
for (int i = 0; i <= 10; i++) {
System.out.print(i);
}
}
}
线程类的读取线程名常用方法
package com.daily022;
public class MyThread2 extends Thread {
public static void main(String[] args) {
// 1、创建任务类的对象
MyThread2 t1 = new MyThread2();
// OPEN1:
// 2、设置任务类的线程名称
// t1.setName("线程1");
// 3、启动线程
t1.start();
}
// OPEN1
// // 线程所要执行的任务
// @Override
// public void run() {
// // 实现1~10的打印输出操作
// for (int i = 0; i <= 10; i++) {
// System.out.println(this.getName() + ":" + i);
// }
// // OPEN1:
线程1:0
线程1:1
线程1:2
线程1:3
线程1:4
线程1:5
线程1:6
线程1:7
线程1:8
线程1:9
线程1:10
// }
// OPEN2:
// 线程所要执行的任务
@Override
public void run() {
// 实现1~10的打印输出操作
for (int i = 0; i <= 10; i++) {
System.out.println(this.getName() + ":" + i);
}
// Thread-0:0
// Thread-0:1
// Thread-0:2
// Thread-0:3
// Thread-0:4
// Thread-0:5
// Thread-0:6
// Thread-0:7
// Thread-0:8
// Thread-0:9
// Thread-0:10
}
}
方式二:通过自定义类实现runnable接口,定义一个【可重复利用】的【任务类】 【方便线程间共享数据】【可以使用匿名内部类】
自定义任务,任务可重复利用、方便线程间共享数据
也可以使用匿名内部类的形式,用于执行一次性的任务操作
在线程类中可以轻易的得到线程的信息id、name;线程任务是完全耦合的,不能给其他线程类复用任务 在runnable任务类中不容易获取线程的信息,但是把任务进行抽离,可以多个线程复用任务 资源共享问题: Thread中的非静态成员变量是不共享的,静态是共享的 在同一个任务类中的非静态成员变量是一样的,所以使用同一个任务的线程--资源是共享的
package com.daily022;
// 定义一个任务类, 实现Runnable接口 【可以复用】【方便线程间共享数据】
public class MyRun implements Runnable {
public static void main(String[] args) {
// 1、创建任务类的对象
MyRun task = new MyRun();
// 2、创建线程,提供任务对象
Thread thread = new Thread(task);
// 3、开启线程
thread.start();
}
// 任务要执行的操作
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println(i);
}
}
}
练习:【任务类】【匿名内部类】实现n的阶乘程序
package com.day0805sileo;
import java.util.Scanner;
public class ThreadDemo {
// 使用匿名内部乐力以及Runnable接口实现统计某个num的阶乘的结果【Scanner输入n】
public static void main(String[] args) {
// 1、 创建一个实现
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// -- Scanner
Scanner sc = new Scanner(System.in);
// 输入数值
System.out.println("请输入一个数值m:");
// int等于的数
int n = sc.nextInt();
// 结果输出为
int result = fun(n);
// 输出结果为
System.out.println(n + "的阶乘结果为:" + result);
}
// 定义n的阶乘
public int fun(int n) {
if (n == 1) {
return 1;
} else {
return n * fun(n - 1);
}
}
});
// 2、启动线程
thread.start();
}
}
【任务类】获取现在对象的名字和【currentThread】获取当前执行的线程对象
package com.daily022;
// 定义一个任务类, 实现Runnable接口 【可以复用】【可以用多个线程进行操作】
public class MyRun2 implements Runnable {
public static void main(String[] args) {
// 1、创建任务类的对象
MyRun2 task = new MyRun2();
// // OPEN1
// // 设置线程名字方法一
// // 2、创建线程,提供任务对象
// Thread thread = new Thread(task);
// thread.setName("线程1");
// System.out.println(thread.getName());
// System.out.println("线程id=" + thread.getId());
// // 线程1
// // 线程id=11
// OPEN2
// 设置线程名字方法二
// 2、创建线程,提供任务对象
// Thread thread = new Thread(Runnable target,String name);
Thread thread = new Thread(task,"线程1");
System.out.println(thread.getName());
System.out.println("线程id=" + thread.getId());
// 线程1
// 线程id=11
System.out.println();
// 3、开启线程
thread.start();
}
// 任务要执行的操作
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
// System.out.println(this.getName()+":"+i);// 这样不行因为Runnable接口中没有该getName方法
// 故此要在这里加上currentThread方法才能使用 源码为以下操作
// public static native Thread currentThread();
// currentThread()获取当前执行的线程对象
System.out.println(Thread.currentThread().getName()+":"+i);
// 线程1:1
// 线程1:2
// 线程1:3
// 线程1:4
// 线程1:5
// 线程1:6
// 线程1:7
// 线程1:8
// 线程1:9
// 线程1:10
}
}
}
练习:火车票抢票【分别使用线程类和任务类来实现】
--京东
--智行
--飞猪
京东抢到了序号为100的火车票
智行抢到了序号为99的火车票
package com.daily022;
public class TicketMain {
public static void main(String[] args) {
// 【任务类】
// TicketTask task = new TicketTask();
// 【线程类】
TicketThread task = new TicketThread();
// 1、创建线程的对象
Thread JD_COM = new Thread(task, "京东");
Thread Intelligent_behavior = new Thread(task, "智行");
Thread Fliggy = new Thread(task, "飞猪");
// 2、启动线程
JD_COM.start();
Intelligent_behavior.start();
Fliggy.start();
}
}
// 【任务类】
//class TicketTask implements Runnable {
// // 定义票数[资源共享]
// public int nums = 100;
//
// // 实现抢票操作
// @Override
// public void run() {
// // 抢票--循环操作
// while (nums > 0) {
// // 获取线程名称
// String name = Thread.currentThread().getName();
// System.out.println(name + "抢到了序号为:" + nums + "的车票");
// // 票数--
// nums--;
// }
// }
//}
//【线程类】
//自定义线程实现抢票操作
class TicketThread extends Thread {
// 定义票数[资源共享-要使用静态]
public static int nums = 100;
public TicketThread() {
super();
}
public TicketThread(String name) {
super(name);
}
// 实现抢票操作
@Override
public void run() {
// 抢票--循环操作
while (nums > 0) {
// 获取线程名称
String name = this.getName();
System.out.println(name + "抢到了序号为:" + nums + "的车票");
// 票数--
nums--;
}
}
}
方式三:通过自定义类实现Callable接口,定义一个可返回数据、可以抛出异常的执行操作
–实现Callable接口、注意指定返回值类型
–使用FutureTask封装Callable接口的对象
–使用Thread类来注入FutureTask对象并创建线程
线程的结果可以通过FutureTask对象的get方法获取
–通常情况都使用Runnable方式,可以重复利用任务类对象、可以在线程间共享数据,并且可以继承其他类
–当需要在线程中返回数据和声明异常时,可以使用Callable方式
package com.day0805sileo;
import java.lang.annotation.Target;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class ThreadMain {
public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
// 1、callable接口任务
MyCallable callable = new MyCallable();
// 2、封装任务类的对象 FutureTask本身就是Runnable
// public class FutureTask implements RunnableFuture {
// public interface RunnableFuture extends Runnable, Future {
FutureTask task = new FutureTask<>(callable);
// 3、构建线程,提供任务类
Thread thread = new Thread(task);
// 4、启动线程
thread.start();
// 5、通过任务类来获取线程的结果
// open1
// Integer result = task.get();// 阻塞
// System.out.println(task.isDone());// 任务是否已经完成
// System.out.println(task.isCancelled());// 任务是否已经完成
Integer result = task.get(2, TimeUnit.SECONDS);// 阻塞3
// 阻塞时间为10s 而且阻塞这里设置的是为2s获取信息, 所以会出现报错
// 所以小于只要设置睡眠时间为小于2s即可 不会出现报错了
// Exception in thread "main"
// java.util.concurrent.TimeoutException
System.out.println(result);
}
}
// 定义Callable任务类 call方法
class MyCallable implements Callable {
// 当前线程任务返回的结果 call(); [有返回值类型,可以抛出异常]
@Override
public Integer call() throws Exception {
// 随机数
Random random = new Random();
// 设置数返回值为1
int ran1 = random.nextInt(10);
int ran2 = random.nextInt(10);
// open1、2 阻塞时间(睡眠时间为10s)
Thread.sleep(10000);
// 返回相加的结果
return ran1 + ran2;
}
}
三种创建方式有什么区别?分别在什么场景下应用?
–新建:创建了线程的对象,分配了内存空间
–就绪:启动了线程,进入就绪状态,等待cpu的调用
–运行:线程在运行中,执行run进行操作
–阻塞:睡眠、等待、“假死状态”
(1) Thread.sleep(); //引起 当前线程阻塞 (2) Thread.join(); //引起当前线程阻塞 (3) Thread.suspend(); //引起 th1 线程阻塞
–死亡:线程结束、出现异常
–Thread.sleep(1000);
–TimeUnit.SECONDS.sleep(1);
// 调用了sleep方法后,线程会进入阻塞状态,释放了cpu执行权,但是没有释放对象锁
// 睡眠结束后,会回到就绪状态,然后和其他就绪状态的线程抢夺资源
package com.day0805sileo;
import java.util.concurrent.TimeUnit;
public class TreadSleepDemo {
// 线程睡眠操作,时间结束后,线程是回到就绪状态,重新抢夺资源
public static void main(String[] args) throws InterruptedException {
// 1、通过sleep方法,实现线程的睡眠(延迟)
System.out.println("你好。。");
// Thread..sleep(2000);//延迟2秒,单位是毫秒
// 2、通过时间单元工具类
TimeUnit.SECONDS.sleep(1);
System.out.println("天气真不错。。。");
}
}
合并:让当前线程进入阻塞状态,直到调用join方法的线程完成之后,再回到当前线程进行操作
线程合并案例1,一个和尚去挑水,另一个和尚负责下水烧饭【要挑水完成,再下水烧饭】
package com.day0805sileo;
public class JoinThreadDemo {
// main主线程 heshang线程
public static void main(String[] args) {
// 创建挑水和尚线程
HeShang heshang = new HeShang();
// 启动线程去挑水
heshang.start();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 另一个和尚进行下水烧饭
System.out.println("另一个和尚进行下水烧饭");
}
}
// 定义一个线程来实现和尚去挑水的操作
class HeShang extends Thread {
@Override
public void run() {
//
System.out.println("和尚去小河挑水");
// 模拟去挑水的时间
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//
System.out.println("和尚挑水回来了");
}
}
//这里是和main方法一起输出的
//和尚去小河挑水
//另一个和尚进行下水烧饭
//睡眠3秒时间后:和尚挑水回来了
package com.day0805sileo;
public class JoinThreadDemo {
// main主线程 heshang线程
public static void main(String[] args) throws InterruptedException {
// 创建挑水和尚线程
HeShang heshang = new HeShang();
// 启动线程去挑水
heshang.start();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 完成挑水(在main线程中合并heshang线程--相当于把HeShang生命周期插入main线程的生命周期)
// heshang.join();//合并
heshang.join(1500);// 可以设置合并的超时时间 记得抛出异常
// 另一个和尚进行下水烧饭
System.out.println("另一个和尚进行下水烧饭");
}
}
// 定义一个线程来实现和尚去挑水的操作
class HeShang extends Thread {
@Override
public void run() {
//
System.out.println("和尚去小河挑水");
// 模拟去挑水的时间
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//
System.out.println("和尚挑水回来了");
}
}
//这里是停顿1.52秒后才输出的另一个和尚进行下水烧饭
//和尚去小河挑水
//另一个和尚进行下水烧饭
//1.48秒后和尚挑水回来了
package daily02;
// 线程合并案例:一个和尚去挑水、另一个和尚负责下水烧饭 [等待一段时间,没有等到则先去扫地,完成之后再下水烧饭]
public class JionThreadDemo2 {
// main线程(主线程) HeShang线程
public static void main(String[] args) throws InterruptedException {
// 创建挑水和尚线程
HeShang heshang = new HeShang();
// 启动线程去挑水
heshang.start();
//
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 完成挑水(在main线程中合并heshang线程--相当于把heshang的生命周期插入到main中去)
// heshang.join();// 合并
heshang.join(1500);// 1.5秒后不等了,等待继续烧饭的时间
// 另一个和尚进行下水烧饭
System.out.println("等待了一段时间后,没等回来,另一个和尚去扫地");
}
}
// 定义一个线程来实现和尚去挑水的操作
class HeShang extends Thread {
@Override
public void run() {
//
System.out.println("和尚去小河挑水");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("和尚挑水回来了");
// 模拟去挑水的时间
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("另一个和尚去下水烧饭。");
}
}
实现2
package com.day0805sileo;
public class JoinThreadDemo {
// main主线程 heshang线程
public static void main(String[] args) throws InterruptedException {
// 创建挑水和尚线程
HeShang heshang = new HeShang();
// 启动线程去挑水
heshang.start();
// try {
// Thread.sleep(20);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// 完成挑水(在main线程中合并heshang线程--相当于把HeShang生命周期插入main线程的生命周期)
// heshang.join();//合并
heshang.join(1000);// 可以设置合并的超时时间 记得抛出异常
while (!heshang.isDown) {
System.out.println("另一个和尚正在扫地。");
//
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 另一个和尚进行下水烧饭
System.out.println("另一个和尚进行下水烧饭");
}
}
// 定义一个线程来实现和尚去挑水的操作
class HeShang extends Thread {
// 标志位
boolean isDown = false;
@Override
public void run() {
//
System.out.println("和尚去小河挑水");
// 模拟去挑水的时间
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//
isDown = true;
//
System.out.println("和尚挑水回来了");
}
}
//和尚去小河挑水
//另一个和尚正在扫地。
//另一个和尚正在扫地。
//和尚挑水回来了
//另一个和尚进行下水烧饭
2、让步yield:使得当前线程让出cpu,再回到就绪状态,和其他线程一起再去抢夺资源
this.yield();
package com.day0805sileo;
public class YelidMain {
public static void main(String[] args) {
// 不让步线程
YeildThread t1 = new YeildThread();
YeildThread t2 = new YeildThread();
YeildThread t3 = new YeildThread();
// 设置让步线程
YeildThread y = new YeildThread("让步线程");
// 启动线程
t1.start();
t2.start();
t3.start();
y.start();
// 【让步线程】现在在执行60步
// 【Thread-1】现在在执行60步
// 【Thread-2】现在在执行60步
// 【Thread-2】现在在执行61步
// 【让步线程】现在在执行61步
// 【Thread-0】现在在执行61步
// 【Thread-1】现在在执行61步
// 【Thread-0】现在在执行62步
// 【让步线程】现在在执行62步
// 【Thread-2】现在在执行62步
// 【Thread-1】现在在执行62步
// 【让步线程】现在在执行63步
// 【Thread-2】现在在执行63步
// 【Thread-1】现在在执行63步
// 【Thread-0】现在在执行63步
// 【Thread-2】现在在执行64步
// 【Thread-1】现在在执行64步
// 【Thread-2】现在在执行100步
// 【Thread-0】现在在执行100步
// 【让步线程】现在在执行100步
// 【Thread-1】现在在执行100步
// 【让步线程】执行让步,回到就绪状态,和其他的线程一起抢夺资源-------
// 【Thread-1】现在在执行101步
// 【Thread-2】现在在执行101步
// 【让步线程】现在在执行101步
// 【Thread-0】现在在执行101步
// 【Thread-0】现在在执行200步
// 【Thread-1】现在在执行200步
// 【让步线程】现在在执行200步
// 【让步线程】执行让步,回到就绪状态,和其他的线程一起抢夺资源-------
// 【Thread-1】现在在执行201步
// 【让步线程】现在在执行201步
// 【Thread-2】现在在执行201步
// 【Thread-0】现在在执行201步
// 【Thread-2】现在在执行202步
// 【Thread-1】现在在执行202步
// 【让步线程】现在在执行202步
// 【Thread-0】现在在执行202步
// 【Thread-1】现在在执行203步
}
}
// 线程让步案例:如果当前线程为让步线程,并且当操作步数能够整除100时候,则当前线程执行让步【让步cpu】
class YeildThread extends Thread {
// 定义一个步数
public int count = 0;
// 提供父类构造器String类型 有参数和无参数
public YeildThread(String name) {
super(name);
}
public YeildThread() {
super();
}
// 重写run
@Override
public void run() {
// 1、获取当前线程名称
String name = this.getName();
// 2、循环
while (true) {
System.out.printf("【%s】现在在执行%d步n", name, count);
// --判断是否为让步线程,操作步数能整除100
if (name.equals("让步线程") && count % 100 == 0) {
// 当前线程执行起步
System.out.printf("【%s】执行让步,回到就绪状态,和其他的线程一起抢夺资源-------n", name, count);
this.yield();// 让步操作
}
// count自增
count++;
// 延迟
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
线程优先级:1-10【值越高,优先级越高,能获得更多的执行机会 】
默认优先级为5
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(3);
t3.setPriority(3);
package com.day0805sileo;
public class YelidMain {
public static void main(String[] args) {
// 不让步线程
YeildThread t1 = new YeildThread("不让步线程1");
YeildThread t2 = new YeildThread("不让步线程2");
YeildThread t3 = new YeildThread("不让步线程3");
// 设置优先级
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(3);
t3.setPriority(3);
// 【不让步线程1】现在在执行56步
// 【不让步线程3】现在在执行56步
// 【让步线程】现在在执行56步
// 【不让步线程2】现在在执行56步
// 【不让步线程2】现在在执行57步
// 【不让步线程1】现在在执行57步
// 【让步线程】现在在执行57步
// 【不让步线程3】现在在执行57步
// 【让步线程】现在在执行58步
// 【不让步线程1】现在在执行58步
// 【不让步线程3】现在在执行58步
// 【不让步线程2】现在在执行58步
// 【不让步线程1】现在在执行59步
// 【不让步线程3】现在在执行59步
// 【让步线程】现在在执行59步
// 【不让步线程2】现在在执行59步
// 【不让步线程2】现在在执行416步
// 【让步线程】现在在执行417步
// 【不让步线程2】现在在执行417步
// 【不让步线程3】现在在执行417步
// 【不让步线程1】现在在执行417步
// 【不让步线程1】现在在执行418步
// 【让步线程】现在在执行418步
// 【不让步线程3】现在在执行418步
// 【不让步线程2】现在在执行418步
// 【不让步线程1】现在在执行419步
// 【让步线程】现在在执行419步
// 【不让步线程3】现在在执行419步
// 【不让步线程2】现在在执行419步
// 【不让步线程1】现在在执行420步
// 【不让步线程2】现在在执行420步
// 【让步线程】现在在执行420步
// 【不让步线程3】现在在执行420步
// 【不让步线程3】现在在执行421步
// 【不让步线程1】现在在执行421步
// 【不让步线程2】现在在执行421步
// 【不让步线程1】现在在执行422步
// 【不让步线程3】现在在执行422步
// 【让步线程】现在在执行422步
// 【不让步线程2】现在在执行422步
// 【让步线程】现在在执行423步
// 设置让步线程
YeildThread y = new YeildThread("让步线程");
// 启动线程
t1.start();
t2.start();
t3.start();
y.start();
}
}
// 线程让步案例:如果当前线程为让步线程,并且当操作步数能够整除100时候,则当前线程执行让步【让步cpu】
class YeildThread extends Thread {
// 定义一个步数
public int count = 0;
// 提供父类构造器String类型 有参数和无参数
public YeildThread(String name) {
super(name);
}
public YeildThread() {
super();
}
// 重写run
@Override
public void run() {
// 1、获取当前线程名称
String name = this.getName();
// 2、循环
while (true) {
System.out.printf("【%s】现在在执行%d步n", name, count);
// --判断是否为让步线程,操作步数能整除100
if (name.equals("让步线程") && count % 100 == 0) {
// 当前线程执行起步
System.out.printf("【%s】执行让步,回到就绪状态,和其他的线程一起抢夺资源-------n", name, count);
this.yield();// 让步操作
}
// count自增
count++;
// 延迟
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3、挂起suspend、唤醒resume:【理解即可】
suspend挂起方法过时不推荐使用(偏死锁、容易造成死锁,所以不推荐使用)
resume唤醒方法过时不推荐使用
package com.day0805sileo01;
public class SuspendMain {
public static void main(String[] args) {
// SuspendThread
SuspendThread t = new SuspendThread();
t.start();
// 睡眠时间
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 突然间老师人有三急 要上厕所
System.out.println("老师去上厕所");
t.suspend();// 挂起点名线程 方法已经过时
// 睡眠时间
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("老师回来了,继续点名");
// 老师回来
t.resume();// 唤起点名线程 方法已经过时
// 老师点名:当前点到序号为:1的学生
// 老师点名:当前点到序号为:2的学生
// 老师点名:当前点到序号为:3的学生
// 老师点名:当前点到序号为:4的学生
// 老师点名:当前点到序号为:5的学生
// 老师点名:当前点到序号为:6的学生
// 老师点名:当前点到序号为:7的学生
// 老师点名:当前点到序号为:8的学生
// 老师点名:当前点到序号为:9的学生
// 老师点名:当前点到序号为:10的学生
// 老师点名:当前点到序号为:11的学生
// 老师点名:当前点到序号为:12的学生
// 老师点名:当前点到序号为:13的学生
// 老师点名:当前点到序号为:14的学生
// 老师点名:当前点到序号为:15的学生
// 老师点名:当前点到序号为:16的学生
// 老师点名:当前点到序号为:17的学生
// 老师点名:当前点到序号为:18的学生
// 老师点名:当前点到序号为:19的学生
// 老师点名:当前点到序号为:20的学生
// 老师去上厕所
// 老师回来了,继续点名
// 老师点名:当前点到序号为:21的学生
// 老师点名:当前点到序号为:22的学生
// 老师点名:当前点到序号为:23的学生
// 老师点名:当前点到序号为:24的学生
// 老师点名:当前点到序号为:25的学生
// 老师点名:当前点到序号为:26的学生
// 老师点名:当前点到序号为:27的学生
// 老师点名:当前点到序号为:28的学生
// 老师点名:当前点到序号为:29的学生
// 老师点名:当前点到序号为:30的学生
}
}
class SuspendThread extends Thread {
@Override
public void run() {
for (int i = 1; i <= 30; i++) {
System.out.println("老师点名:当前点到序号为:" + i + "的学生");
// 延迟
try {
Thread.sleep(150);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
4、中断interrput:【理解即可】
调用interrupt()会打断一下线程,由于受到sleep、wait或者 join方法的影响,程序会抛出InterruptedException,异常被处理后程序会继续往下执行
package com.day0805sileo01;
public class InterrupetMain {
public static void main(String[] args) {
TalkThread t = new TalkThread();
t.start();
//
try {
Thread.sleep(2500);// 当睡眠被打断的时候,就会出现InterruptedException异常
} catch (InterruptedException e) {
e.printStackTrace();
}
// 突然,孩子他妈来了,和黄爸爸有要是商谈【中断交流】
t.interrupt();// 打断就会出现异常InterruptedException
// java.lang.InterruptedException: sleep interrupted
// 交流结束
// at java.lang.Thread.sleep(Native Method)
// at com.day0805sileo01.TalkThread.run(InterrupetMain.java:30)
}
}
class TalkThread extends Thread {
@Override
public void run() {
// 开个家长会,老师和家长正在深入交流
System.out.println("李老师,和黄爸爸在深入交流孩子的学习情况");
// 根据交流的时间
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// e.printStackTrace();
System.out.println("交流被打断,然后改日再聊!");// 预处理操作
}
// 输出结果
System.out.println("交流结束");
}
}
5、停止:调用stop()会结束线程和终止线程的生命周期
后台线程:也称为守护线程,主要做一些幕后工作,比如jvm的垃圾回收机制;后台线程和普通线程的创建方式是一样的,但是要使用thread.setDaemon(true)进行设置
注意:后台线程的生命周期和主线程的生命周期是一致的、绑定的;当主线程死亡,则后台线程也跟着死亡
package com.day0805sil02;
public class StopDemo {
public static void main(String[] args) {
TalkThread t = new TalkThread();
t.start();
//
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.stop();// 停止线程、结束线程
// 李老师,和黄爸爸在深入交流孩子的学习情况
}
}
class TalkThread extends Thread {
@Override
public void run() {
// 开个家长会,老师和家长正在深入交流
System.out.println("李老师,和黄爸爸在深入交流孩子的学习情况");
// 根据交流的时间
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// e.printStackTrace();
System.out.println("交流被打断,然后改日再聊!");// 预处理操作
}
// 输出结果
System.out.println("交流结束");
}
}
终止线程的生命周期
注意:后台线程的生命周期和主线程的生命周期绑定的,主线程死亡,后台线程也跟着死亡
package com.day0805sil02;
public class DaemonMain {
public static void main(String[] args) throws InterruptedException {
// 创建线程
DaemonThread damon = new DaemonThread();
// 设置为后台线程
damon.setDaemon(true);
// open1启动线程
damon.start();// 后台线程执行数据检测操作。。。
// open2主线程执行5秒
Thread.sleep(5000);
// 后台线程执行数据检测操作。。。
// 后台线程执行数据检测操作。。。
// 后台线程执行数据检测操作。。。
// 后台线程执行数据检测操作。。。
// 后台线程执行数据检测操作。。。
}
}
// 后台数据检测工作
class DaemonThread extends Thread {
@Override
public void run() {
while (true) {
System.out.println("后台线程执行数据检测操作。。。");
//
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}



