当前位置: 首页 > news >正文

java加强 -多线程 -创建与常用方法

线程(Thread)是一个程序内部的一条执行流程。程序中如果只有一条执行流程,那这个程序就是单线程程序。多线程是指从软硬件上实现的多条执行流程的技术(多条线程由CPU调度执行)。例如电脑下载软件时两个软件可以同时下载。

创建线程

方式一、继承Thread类

定义一个子类继承Thread类,使其成为线程类,然后重写父类中的run=方法,当调用子线程执行时执行的就是run方法中的内容。

示例

package CreateDemo;public class ThreadDemo1 {//main方法本身是由一条主线程负责推进执行的,此时还具有t1线程的存在,实现了多线程public static void main(String[] args) {//目标:认识多线程,掌握创建线程的方式一:继承Thread类//4、创建一个线程对象,代表线程MyThread t1 = new MyThread();//5、调用start方法启动线程t1.start();for (int i = 0; i < 5; i++){System.out.println("主线程输出:"+i);}}
}
//1、定义一个子类继承Thread类,成为一个线程类
class MyThread extends Thread {//2、重写run方法@Overridepublic void run() {//3、在run方法中编写线程要执行的代码for (int i = 0; i < 5; i++){System.out.println("子线程输出:"+i);}}
}
//优点:编码简单
//缺点:线程类已经继承了Thread类,不能继承其他类,不利于功能的扩展

当需要执行多线程时,先创建一个线程类对象,然后调用其的start()方法就可以实现主线程和子线程共同执行。此时主线程和子线程是同步执行的,比如子线程输出一个1接着主线程也输出一个1,但也有某个线程因为执行速度快一次性跑完的情况,可以多跑跑代码测试。

这个创建方式编码简单,但因为类只能继承一个父类,因此不能再继承其他类,不利于功能的扩展。

方式二:实现Runnable接口创建

创建一个类实现Runnable接口,重写Runnable接口中的run方法。当需要多线程执行时,先用Runnable的实现类创建一个线程任务对象,然后用Thread包装线程任务对象使其成为线程,再调用start方法执行Runnable的实现类中的run方法。

package CreateDemo;public class ThreadDemo2 {public static void main(String[] args) {//掌握多线程的创建方式二:实现Runnable接口创建
//        3、创建线程任务类的一个对象代表一个线程任务Runnable r = new MyRunnable();//4、创建一个线程对象,代表线程Thread t1 = new Thread(r);//5、调用start方法启动线程t1.start();for (int i = 0; i < 5; i++){System.out.println("主线程输出:"+i);}}
}//1、定义一个线程任务类实现Runnable接口
class MyRunnable implements Runnable{//2、重写run方法,设置线程任务@Overridepublic void run() {for (int i = 0; i < 5; i++){System.out.println("子线程输出:"+i);}}
}
//优点:线程任务类只是实现接口,可以继续继承其他类,实现其他接口,扩展性强
//缺点:需要多一个Runnable对象

当然还有另一种实现Runnable接口的方案,无需创建新的类,直接用匿名内部类的方法实现Runnable接口中的run方法,再包装,执行。也可以直接Thread包装Runnable接口的匿名内部类。

package CreateDemo;public class ThreadDemo2_2 {public static void main(String[] args) {//目标:掌握多线程的创建方式二:使用Runnable接口的匿名内部类创建Runnable r = new Runnable(){@Overridepublic void run() {for (int i = 0; i < 5; i++){System.out.println("子线程输出:"+i);}}};//直接在创建Thread对象时,传入Runnable接口的匿名内部类对象new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 5; i++){System.out.println("子线程输出2:"+i);}}}).start();Thread t1 = new Thread(r);//5、调用start方法启动线程t1.start();for (int i = 0; i < 5; i++){System.out.println("主线程输出:"+i);}}
}

因为Runnable是一个函数式接口,以上代码还可以通过Lambda进行代码简化。

这样实现多线程可以继续继承其他类,功能延展性比前一个方法好,但要多创建一个Runnable对象。

方式三:实现Callable接口

前两种方案虽然实现了同时进行多个线程,但却不能在合适的时间获取线程的结果。例如我需要一个线程获取1-100之间的数量和,但我却不能判断需要在什么时候获取这个线程的结果,因为几个线程是交替进行的,无法确定哪个位置会跑完哪个线程。此时,我们就需要通过实现Callable接口来创建线程任务对象,Callable接口有独特的优势,它可以获取线程执行完毕后的结果。

步骤:定义一个Callable接口的实现类,创建该实现类的对象,然后再把Callable的实现类对象包装成FutureTask对象(线程任务对象)

package CreateDemo;import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;public class ThreadDemo3 {public static void main(String[] args) {//掌握多线程的创建方式3:实现Callable接口,方式3的优势,可以获取线程执行完毕后的结果//3、创建一个Callable接口的实现类对象Callable<String> c1 = new MyCallable(100);//4、把Callable对象封装成一个FutureTask对象(线程任务对象),/*** 未来任务对象的作用* 本身是一个Runnable的线程任务对象,可以交给Thread线程对象处理* 获取线程执行结果后的结果*/FutureTask<String> ft = new FutureTask<>(c1);   //public FutureTask(Callable<V> callable)//5、创建一个线程对象,代表线程Thread t1 = new Thread(ft);//6、调用start方法启动线程t1.start();Callable<String> c2 = new MyCallable(50);FutureTask<String> ft2 = new FutureTask<>(c2);Thread t2 = new Thread(ft2);t2.start();//获取线程执行结果的结果try {//如果发现第一个线程没有执行完毕会让出cpu,等第一个线程执行完毕后才会向下执行System.out.println(ft.get());}catch (Exception e) {e.printStackTrace();}try {//如果发现第二个线程没有执行完毕会让出cpu,等第二个线程执行完毕后才会向下执行System.out.println(ft2.get());}catch (Exception e){e.printStackTrace();}}
}
//定义一个Callable接口的实现类
class MyCallable implements Callable<String> { //<>内的类型就是call方法的返回值类型private int n;public MyCallable(int n) {this.n = n;}//实现call方法,定义线程执行体@Overridepublic String call() throws Exception {int sum = 0;for (int i = 1; i <= n; i++) {sum += i;}return "子线程计算1-"+n+"的和为:"+sum;}
}

FutureTask对象本身是一个Runnable的线程任务对象,可以交给Thread线程对象处理,当需要获取线程结果时,就调用FutureTask对象的get方法以获得值。

线程对象的常用方法

1、命名

线程对象的默认名为Thread -索引

对线程对象命名有两种方案,一种是直接用线程对象的setName方法,即变量名.setName(“名字”);

还有一种是在子类中写一个有参构造器接收名字,在子类的有参构造器中将名字用super方法传给父类.

2、获取线程对象名

对象名.getName()

package ThreadApiDemo;public class ThreadApiDemo1 {public static void main(String[] args) {Runnable r = new MyThread();//包装线程任务对象时可以直接用有参构造器命名,Thread有这种构造器Thread t = new Thread(r,"3号线程");//目标:搞清楚线程的常用方法MyThread t1 = new MyThread("1号线程");//有参构造器//设置名字
//        t1.setName("一号线程");t1.start();System.out.println("线程名称:"+t1.getName());   //默认线程名称:Thread-索引MyThread t2 = new MyThread("2号线程");
//        t2.setName("二号线程");t2.start();System.out.println("线程名称:"+t2.getName());for (int i = 0; i < 5; i++){System.out.println("主线程输出:"+i);}//哪个线程调用了currentThread方法,这个线程对象就拿到哪个线程Thread m = Thread.currentThread();//主线程m.setName("主线程");System.out.println("主线程名称:"+m.getName());//主线程名字(main)}
}//1、定义一个子类继承Thread类,成为一个线程类
class MyThread extends Thread {//2、重写run方法@Overridepublic void run() {//3、在run方法中编写线程要执行的代码for (int i = 0; i < 5; i++){System.out.println(Thread.currentThread().getName()+"输出:"+i);}}public MyThread(String name){super(name);}public MyThread(){super();}
}

3、Sleep方法(线程休眠),可以让线程停止一段你设定的时间然后再继续执行

对象名.sleep(时间)        (时间单位是毫秒)

package ThreadApiDemo;public class ThreadApiDemo2 {public static void main(String[] args) {//目标:搞清楚Thread类的Sleep方法(线程休眠)for (int i = 0; i < 10; i++) {System.out.println(i);try {//让当前执行的线程进入休眠状态,时间到了以后才继续执行Thread.sleep(1000); //1000ms = 1s} catch (InterruptedException e) {e.printStackTrace();}}}
}

4、join方法(线程插队)

让这个线程先执行完再执行其他线程

对象名.join()

package ThreadApiDemo;public class ThreadApiDemo3 {public static void main(String[] args) {//目标:搞清楚join方法:线程插队:让调用这个方法的线程先执行完MyThread2 t1 = new MyThread2();t1.start();for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + "输出:" + i);if (i==0){try {t1.join();  //让t1线程先执行完,然后再执行主线程} catch (InterruptedException e) {e.printStackTrace();}}}}
}class MyThread2 extends Thread {//2、重写run方法@Overridepublic void run() {//3、在run方法中编写线程要执行的代码for (int i = 0; i < 5; i++){System.out.println(Thread.currentThread().getName()+"输出:"+i);}}public MyThread2(String name){super(name);}public MyThread2(){super();}
}

相关文章:

  • 如何完美安装GPU版本的torch、torchvision----解决torch安装慢 无法安装 需要翻墙安装 安装的是GPU版本但无法使用的GPU的错误
  • ​Docker 网络
  • vue3_flask实现mysql数据库对比功能
  • 一款适配国内的视频软件,畅享大屏与局域网播放
  • sparkSQL读入csv文件写入mysql(2)
  • STM32SPI实战-Flash模板
  • html文件cdn一键下载并替换
  • 计算机图形学中MVP变换的理论推导
  • R for Data Science(3)
  • windows环境下c语言链接sql数据库
  • Spring 框架线程安全的五大保障策略解析
  • 山东大学计算机图形学期末复习11——CG13上
  • NAT(网络地址转换)逻辑图解+实验详解
  • symfonos: 2靶场
  • C++(21):fstream的读取和写入
  • StarRocks Community Monthly Newsletter (Apr)
  • 系统性能不达标,如何提升用户体验?
  • 嵌入式学习的第二十二天-数据结构-栈+队列
  • NC016NC017美光固态芯片NC101NC102
  • LLMs:《POE报告:2025年春季人工智能模型使用趋势》解读
  • 魔都眼|邮轮港国际帆船赛启动,120名中外选手展开角逐
  • 广西鹿寨一水文站“倒刺扶手”存安全隐患,官方通报处理情况
  • 网约车座椅靠背张贴“差评者得癌症”,如祺出行:未收到投诉无法处理
  • 5吨煤炭“瞬间蒸发”?掺水炭致企业损失千万,腐败窝案曝光
  • 2025财政观察|长三角“三公”经费普降,钱要用在刀刃上
  • 阿尔巴尼亚执政党连续第四次赢得议会选举,反对党此前雇用特朗普竞选经理