线程Thread

这篇具有很好参考价值的文章主要介绍了线程Thread。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


一、概念

1、进程

  • 进程就是正在运行中的程序

2、线程

  • 是1个进程(程序内部)的1条执行路径
  • 单线程:1个进程中只有1个线程(1条执行路径)
  • 多线程:1个进程中包含多个线程(多条执行路径)
  • 线程之间堆内存、方法区内存共享;但是栈内存独立,1个线程一个栈

3、CPU与线程的关系

  1. 单核CPU:不能够做到真正的多线程并发,因为在一个时间单元内,只能执行一个线程的任务,多个线程谁获取时间片运行谁,每个线程获取时间片的概率相等,可能:t1、t2、t2、t2;给人一种多线程并发的感觉:其实是由于CPU的处理速度极快,多个线程之间频繁切换执行,跟人来的感觉是多个事情同时在做

4、并行、并发

  1. 并行:多核CPU同时执行多个任务。比如:多个人同时做不同的事
  2. 并发:单核CPU同时执行多个任务。比如:多个人做同一件事

5、线程的生命周期

  1. 新建状态
    • 新建了线程对象,还没调用start方法
  2. 就绪状态
    • 线程调用了start方法等待获取CPU时间片
    • 表示当前线程具有抢夺CPU时间片的权力
  3. 运行状态
    • 线程对象开始执行run方法
    • run方法的开始执行标志着这个线程进入运行状态,当之前占有的CPU时间片用完之后,会重新回到就绪状态继续抢夺CPU时间片,当再次抢到CPU时间之后,会重新进入run方法接着上一次的代码继续往下执行
  4. 阻塞状态
    • 当一个线程遇到阻塞事件,例如:sleep方法、获取synchronized排他锁失败(因为锁被其它线程所占用)等,此时线程会进入阻塞状态,阻塞状态的线程会放弃之前占有的CPU时间片,之前的时间片没了需要再次回到就绪状态抢夺CPU时间片
  5. 死亡状态
    • run方法执行完毕或者因异常退出了run方法,该线程生命周期结束

二、创建

1、继承Thread

  • class Thread implements Runnable
  • 缺点:
    • 由于java是单继承的,这导致继承了Thread后就不能在继承其它类了;在实际开发中会经常继承某个超类来复用其中的方法,这导致两者不能同时继承
    • 继承线程后重写run方法来定义任务,这又导致我们将任务直接定义在线程上使得线程只能做该任务,无法并发执行其他任务,重用性变差
public class HandleMsg extends Thread{

    /** 线程标识 */
    private String threadKey;

    /** 构造方法用来区分不同线程便于测试 */
    public HandleMsg(String threadKey){
        this.threadKey=threadKey;
    }

    @Override
    public void run(){
        for(int i=0;i<10;i++){
            System.err.println(threadKey+":run");
        }
    }

}

//匿名内部类lambda
Thread t1=new Thread(()->{
	for(int i=0;i<10;i++) {
		System.err.println("t1:run");
	}
};

//创建2个线程对象
HandleMsg h1=new HandleMsg("h1");
HandleMsg h2=new HandleMsg("h2");

//启动线程,开始执行实现的run方法
h1.start();
h2.start();

2、实现Runnable接口

  • 优点:线程和线程执行的任务分离
public class HandleMsg implements Runnable{

    /** 线程标识 */
    private String threadKey;

    /** 构造方法用来区分不同线程便于测试 */
    public HandleMsg(String threadKey){
        this.threadKey=threadKey;
    }

    @Override
    public void run(){
        for(int i=0;i<10;i++){
            System.err.println(threadKey+":run");
        }
    }

}

//创建2个任务对象
HandleMsg h1=new HandleMsg("h1");
HandleMsg h2=new HandleMsg("h2");

//将任务1交给线程1
Thread t1=new Thread(h1);
//将任务2交给线程2
Thread t2=new Thread(h2);

//启动线程,开始执行任务的run方法
t1.start();
t2.start();

3、实现Callable接口

  • FutureTask implements RunnableFutureRunnableFuture<V> extends Runnable
  • 优点
    • 线程和线程执行的任务分离
    • 有返回值
    • 可以声明抛出的异常
//Callable的泛型就是重写的call方法的返回值类型
public class HandleMsg implements Callable<String>{

    /** 线程标识 */
    private String threadKey;

    /** 构造方法用来区分不同线程便于测试 */
    public HandleMsg(String threadKey){
        this.threadKey=threadKey;
    }

    @Override
    public String call() throws Exception{
        for(int i=0;i<10;i++){
            System.err.println(threadKey+":run");
        }
        return threadKey;
    }

}

//创建2个任务对象
HandleMsg h1=new HandleMsg("h1");
HandleMsg h2=new HandleMsg("h2");

//创建FutureTask类包装任务对象,泛型就是任务类实现Callable的泛型,也就是call方法返回值的类型
FutureTask<String> f1=new FutureTask<>(h1);
FutureTask<String> f2=new FutureTask<>(h2);

//将FutureTask对象交给线程
Thread t1=new Thread(f1);
Thread t2=new Thread(f2);

//启动线程,开始执行任务的run方法
t1.start();
t2.start();

//获取返回值
String result1=f1.get();
String result2=f2.get();

三、API

1、获取运行使用的线程

//在哪个方法执行就获取执行该方法的线程
Thread thread=Thread.currentThread();

2、唯一标识

long getId();

3、线程名

String getName();

//线程启动之前可以设置线程名
void setName(String name);

4、优先级

  • 线程有10个优先级,用1-10表示,默认为5
int getPriority();

//启动之前设置
//线程无法主动获取cpu时间片,唯一可以干涉线程调度工作的方式就是修改线程的优先级,最大程度的改善获取cpu时间片的几率,理论上,线程优先级越高的线程获取cpu时间片的次数越多
void setPriority(int newPriority);

5、是否处于活动状态

boolean isAlive();

6、守护线程

  • 守护线程又称为后台线程,默认创建出来的线程都是普通线程或称为前台线程
  • 当进程结束时,所有正在运行的守护线程都会被强制中断
  • 进程的结束:当一个进程中没有任何前台线程时即结束
  • main主线程就是前台线程,不受其他线程影响,分配其他线程后接着干自己的事,其他线程执行的时候,main线程可能已经结束了
//是否为守护线程
boolean isDaemon();

//启动之前设置
void setDaemon(boolean on);

7、join

  • 作用是:让当前执行的线程陷入等待(内部调用了wait方法)。
    • 永久等待:其实现原理是不停的检查当前线程是否存活,该线程的任务执行完毕后就会处于死亡状态,如果存活则说明任务还未执行完毕-继续等待
  • 线程启动之后调用

1、API

//等待线程执行完任务后再往下执行,join(0);
void join();

//等待线程执行一段时间后再往下执行,无论线程任务是否执行完毕,单位:毫秒
//若指定的时间>线程任务执行时间,则线程任务执行完就会往下运行
//若指定的时间<线程任务执行时间,则达到指定时间就往下运行,线程任务继续执行,只是不再等待而已
void join(long millis);

2、有无join对比

//1、程序正常运行顺序是不会等待线程任务执行完毕,就会往下执行
Thread t1=new Thread(()->{
	for(int i=0;i<5;i++){
		System.err.println(i);
	}
});
t1.start();

System.err.println("next task");

// 输出结果
//		next task
//		0
//		1
//		2
//		3
//		4


//2、调用join
Thread t1=new Thread(()->{
	for(int i=0;i<5;i++){
		System.err.println(i);
	}
});
t1.start();

t1.join();

System.err.println("next task");

//		0
//		1
//		2
//		3
//		4
//		next task

8、yield

  • 线程让步
  • 暂停(不是终止)当前正在执行的线程任务,让其它具有相同优先级或更高优先级的等待的线程执行任务(其它也会包含暂停的线程,所以有可能刚暂停就执行)
  • 暂停的线程状态变化:运行状态 -> 就绪状态
  • 暂停期间不会释放锁,所以其他线程获取不到锁

9、sleep

  • 使线程睡眠
  • sleep的睡眠期间不会释放锁,所以其它线程获取不到锁
  • 睡眠线程的状态变化:运行状态 -> 阻塞状态 -> 就绪状态
//Thread的静态方法,单位:毫秒
static void sleep(long millis) throws InterruptedException;
  • sleep和wait的区别
sleep wait
属于Thread类 属于Object类
可以在任何地方使用 wait、notify、notifyAll 只能在同步方法、同步控制块里面使用
睡眠期间不会释放锁 会释放锁,而且会将当前线程加入到等待队列中
不需要唤醒 可以被notify、notifyAll唤醒

10、线程中断

  • 只是打断线程的睡眠,不会终止线程的继续执行
//线程是否中断
boolean isInterrupted();

//中断线程睡眠
Thread t1=new Thread(()->{
	System.err.println("run......");
	try{
		//睡眠10s
		Thread.sleep(10000L);
	}catch(InterruptedException e){
		e.printStackTrace();
	}
	System.err.println("end......");
});

//启动线程
t1.start();

//中断睡眠
//线程不会睡眠10s,而是被中断,抛出InterruptedException,捕获该异常后,继续执行后续的代码
t1.interrupt();

System.err.println("next task");

// 执行结果
//		next task
//		run......
//		end......

文章来源地址https://www.toymoban.com/news/detail-667451.html

到了这里,关于线程Thread的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java中的Thread线程的简单方法介绍和使用详细分析】

    提示:若对Thread没有基本的了解,可以先阅读以下文章,同时部分的方法已经在如下两篇文章中介绍过了,本文不再重复介绍!! 【Java中Tread和Runnable创建新的线程的使用方法】 【Java中的Thread线程的七种属性的使用和分析】 提示:以下是本篇文章正文内容,下面案例可供参

    2024年02月15日
    浏览(39)
  • 【Java系列】详解多线程(二)——Thread类及常见方法(上篇)

    个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【Java系列专栏】【JaveEE学习专栏】 本专栏旨在分享学习Java的一点学习心得,欢迎大家在评论区交流讨论💌 我们先来回顾一下线程与进程之间的联系。 我们知道多进程

    2024年02月04日
    浏览(46)
  • Java 高级应用-多线程-(一)实现 Runnable 接口与继承 Thread 类

    1.1 程序、进程与线程 • 程序(program):为完成特定任务,用某种语言编写的一组指令的集合。即指一段 静态的代码,静态对象。 • 进程(process):程序的一次执行过程,或是正在内存中运行的应用程序。如:运行 中的 QQ,运行中的网易音乐播放器。 – 每个进程都有一

    2024年02月08日
    浏览(55)
  • 【Java练习题汇总】《第一行代码JAVA》多线程篇,汇总Java练习题——线程及多线程概念、Thread 类及 Runnable 接口、线程状态、synchronized同步操作...

    一、填空题 Java 多线程可以依靠________ 、________ 和________ 三种方式实现。 多个线程操作同一资源的时候需要注意________,依靠________ 实现,实现手段是:________ 和________,过多的使用,则会出现________ 问题。 Java 程序运行时,至少启动________ 个线程,分别是________ 和_

    2024年02月16日
    浏览(54)
  • JAVA深化篇_29—— 线程使用之线程联合以及Thread类中的其他常用方法【附有详细说明及代码案例】

    线程联合 当前线程邀请调用方法的线程优先执行,在调用方法的线程执行结束之前,当前线程不能再次执行。线程A在运行期间,可以调用线程B的join()方法,让线程B和线程A联合。这样,线程A就必须等待线程B执行完毕后,才能继续执行。 join方法的使用 join()方法就是指调用该

    2024年02月05日
    浏览(46)
  • Java/Python/Go不同开发语言在进程、线程和协程的设计差异

    在多线程项目开发时,最常用、最常遇到的问题是 1,线程、协程安全 2,线程、协程间的通信和控制 本文主要探讨不同开发语言go、java、python在进程、线程和协程上的设计和开发方式的异同。 进程 进程是 操作系统进行资源分配的基本单位,每个进程都有自己的独立内存空

    2024年01月23日
    浏览(48)
  • C#基础--线程Thread和线程池ThreadPool

    1. 开启一个线程 ThreadStart 是属于System.Threading 中的一个内置委托 ParameterizedThreadStart 是属于System.Threading 中的一个内置委托 2. 暂停/恢复线程 无法实时的去 “暂停 ” 或者 “恢复” 线程,因为线程是由系统调度执行的,而且中间存在一个延时现象,不可能直接帮你执行 3. 终结

    2024年02月16日
    浏览(33)
  • 【多线程】Thread类

    线程是操作系统中的概念,操作系统内核实现了线程这样的机制,并且对用户层提供了一些 API 供用户使用(如 Linux 中的 pthread 库)。 所以本身关于线程的操作,是依赖操作系统提供的的 API,而 Java 的 JVM 已经把很多操作系统提供的功能封装好了,我们就不需要学习系统原生的

    2024年02月01日
    浏览(37)
  • 线程Thread

    进程就是正在运行中的程序 是1个进程(程序内部)的1条执行路径 单线程:1个进程中只有1个线程(1条执行路径) 多线程:1个进程中包含多个线程(多条执行路径) 线程之间堆内存、方法区内存共享;但是栈内存独立,1个线程一个栈 单核CPU:不能够做到真正的多线程并发

    2024年02月11日
    浏览(81)
  • 【多线程】Thread 类 详解

    继承 Thread 来创建一个线程类,并重写 run() 方法 创建 MyThread 类的实例 调用 start 方法启动线程 注意:只有调用 start 函数才真正的创建了一个线程。 更推荐使用这种方法, 因为 Runnable 只是描述了一个任务,至于任务通过进程、线程、线程池还是什么来执行的,Runnable 并不关

    2024年02月09日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包