您的位置:首页 > 健康 > 美食 > 如何进行域名备案_网站免费大全_贵阳百度推广电话_推广软文怎么写

如何进行域名备案_网站免费大全_贵阳百度推广电话_推广软文怎么写

2025/2/23 13:33:01 来源:https://blog.csdn.net/2303_80341387/article/details/143432308  浏览:    关键词:如何进行域名备案_网站免费大全_贵阳百度推广电话_推广软文怎么写
如何进行域名备案_网站免费大全_贵阳百度推广电话_推广软文怎么写

文章目录

  • 1.认识线程
    • 1.1 概念
      • 1.1.1 线程是什么
      • 1.1.2 为啥要有线程
      • 1.1.3 进程和线程的区别
      • 1.1.4 Java的线程和操作系统线程的关系
    • 1.2创建线程
      • 1.2.1 方法1继承Thread类
      • 1.2.2 方法2实现Runnable接口
      • 1.2.3 其他变形
    • 1.3多线程的优势-增加运行速度
  • 2.Thread 类及常见方法
    • 2.1Thread的常见构造方法
    • 2.2Thread的几个常见属性
    • 2.3后台线程和前台线程
    • 2.4 中断一个线程

1.认识线程

1.1 概念

1.1.1 线程是什么

多进程可以充分利用CPU资源去处理一些复杂业力,从而提升业务的处理效率。

创建进程—>申请资源—>加入PCB链表—>销毁进程—>释放资源—>把该进程从PCB链表中删除。

其中申请资源和释放资源对系统的性能影响比较大,涉及到内存和文件资源,处理一件事申请一份资源就够了,基于这样的思想,引出了线程的概念。线程用的是进程启动时从操作系统中申请的资源,线程也可以叫做轻量级的进程。

当创建一个进程的时候,每个进程都会包含一个线程,这个线程叫做主线程。每一个进程相当于一个公司,每个线程就相当于公司中的员工。

1.1.2 为啥要有线程

线程的优势:

  1. 线程的创建速度比进程快
  2. 线程的销毁速度比进程快
  3. 线程的CPU调度的速度比进程快

1.1.3 进程和线程的区别

进程和进程之间,涉及的各种资源彼此之间不受影响,也就是说进程与进程之间是相互独立的。

一个进程内线程之间是容易受到影响的。

通过多线程的方式可以提高程序处理任务的效率,创建进程的个数,根据CPU逻辑处理器的数量来作为参考。

问:如果无限制的创建线程,会不会进一步提升效率?
答:不一定。 当线程数小于逻辑处理器数时,会提升效率;当线程数大于逻辑处理器数时,由于过多的线程在阻塞等待状态,并没有真正的发挥并发的效果,反而因为创建线程消耗了系统资源。

问:会不会出现线程争抢资源的问题 ?
答:有可能会出现。某一个线程出现问题,就会影响其他的线程,从而影响整个进程。如果一个线程崩溃就会导致整个进程崩溃。

进程与线程的区别:

  1. 进程中包含线程,至少有一个主线程。
  2. 进程是申请资源的最小单位。
  3. 线程是CPU调度的最小单位。
  4. 线程共享进程申请来的所有资源。
  5. 一个线程如果崩溃了,就会影响整个进程。

1.1.4 Java的线程和操作系统线程的关系

线程是轻量级的进程,是操作系统的该娘,但是操作系统提供了一些API(应用程序编程接口,别人写好的一些函数/方法,直接使用即可

  • List item

)供程序员使用。每个操作系统提供的API都不一样。Java对不同操作系统的API进行了封装,对外统一提供了一种调用方法,在Java中提供了Thread类(标准库中的线程类)

1.2创建线程

1.2.1 方法1继承Thread类

自定义的线程是一个类,run方法

public class Demo01_Thread {public static void main(String[] args) {MyThread01 myThread01 = new MyThread01();myThread01.start();//启动线程,申请操作系统中的PCB }
}//自定义一个线程类,继承JDK中的Thread类
class MyThread01 extends Thread{//定义线程的任务,根据业务需求,写代码逻辑即可。@Overridepublic void run() {while (true){System.out.println("hello my thread....");}}
}

输出结果:
在这里插入图片描述

启动线程之后,一个Java中的Thread对象就和操作系统中的PCB相对应。

操作系统中的线程PCB 和 Java中的线程,Thread类的一个对象,是对PCB的一个抽象。
Java中创建一个线程对象---->JVM调用系统中的API—>创建系统 中的线程。(系统中的线程才参与CPU的调度)

定义两个线程

public class Demo02_Thread {public static void main(String[] args) throws InterruptedException {MyThread myThread = new MyThread();myThread.start();while (true){Thread.sleep(1000);System.out.println("hello main thread....");}}
}
class MyThread extends Thread{@Overridepublic void run() {while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("hello my thread....");}}
}

输出结果:
在这里插入图片描述

两个线程同时进行,互不干扰,线程的执行顺序没有什么规律,这个和CPU调度有关,由于CPU调度是抢占式执行的,所以哪个线程占用当前CPU资源是不确定的。

Thread类中的run()方法和start()方法之间的区别?

  1. start()方法,是真实的申请系统线程PCB,从而启动一个线程,参与CPU调度。
  2. run()方法,定义线程时指定线程要执行的任务,只是Java对象的一个普通方法而已。

可以通过 JDK安装目录\bin目录下的jconsole.exe(JDK提供的一个查看JVM运行状态的工具)查看JVM中线程的状态。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2.2 方法2实现Runnable接口

public class Demo03_Thread {public static void main(String[] args) throws InterruptedException {//创建Runnable的实例MyRunnable01 myRunnable01 = new MyRunnable01();//创建线程Thread thread = new Thread(myRunnable01);//线程需要执行什么任务就对应的Runnable即可//启动线程,创建PCB,参与CPU调度thread.start();while (true){Thread.sleep(1000);System.out.println("hello main thread....");}}
}//单独定义了线程的任务,将线程类和业务解耦
class MyRunnable01 implements Runnable{//实现具体的任务@Overridepublic void run() {while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("hello my runnable...");}}
}

输出结果:
在这里插入图片描述

1.2.3 其他变形

函数式接口:接口中只定义一个方法。

1. 通过Thread匿名内部类的方式创建线程

public class Demo05_ThreadCreat {public static void main(String[] args) {Thread thread = new Thread(){@Overridepublic void run() {while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("通过Thread匿名内部类的方式创建线程...");}}};thread.start();}
}

输出结果:
在这里插入图片描述

  1. 创建了一个Thread类的子类,但没有为子类定义类名,匿名
  2. 在0里可以编写子类的代码定义,写法与正常类的实现方式相同
  3. 创建好的匿名内部类的实例赋值给thread变量

2. 通过Runnable接口的匿名内部类的方式创建线程

public class Demo06_ThreadCreate {public static void main(String[] args) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("通过Runnable接口匿名内部类的方式创建线程...");}}});thread.start();}
}

输出结果:
在这里插入图片描述

3. 通过lambda表达式创建线程(推荐使用)

public class Demo07_ThreadCreate {public static void main(String[] args) {Thread thread = new Thread(()->{System.out.println("通过Lambda表达式创建线程...");});thread.start();}
}

输出结果:
在这里插入图片描述

1.3多线程的优势-增加运行速度

情景:自增两个10亿次。

public class Demo01_Thread {public static long count = 10_0000_0000l;public static void main(String[] args) throws InterruptedException {//串行serial();//并行concurrency();}private static void concurrency() throws InterruptedException {//记录开始时间long begin = System.currentTimeMillis();//定义两个线程,分别进行累加操作//第一个线程Thread thread01 = new Thread(()->{long a = 0l;for (int i = 0; i < count; i++) {a++;}});thread01.start();//第二个线程Thread thread02 = new Thread(()->{long a = 0l;for (int i = 0; i < count; i++) {a++;}});thread02.start();//等待thread01和thread02两个线程执行完成thread01.join();thread02.join();//记录结束时间long end = System.currentTimeMillis();System.out.println("并行执行耗时:" + (end - begin));}private static void serial() {//记录开始时间long begin = System.currentTimeMillis();long a = 0l;for (int i = 0; i < count; i++) {a++;}long b = 0l;for (int i = 0; i < count; i++) {b++;}//记录结束时间long end = System.currentTimeMillis();System.out.println("串行执行耗时:" + (end - begin));}
}

输出结果:

串行执行耗时:1937
并行执行耗时:1079

通过多线程的方式,可以明显的提升效率,并行的耗时是串行的一半多一点的时间(有创建线程的消耗)。

问:如果仅将10亿改成10万,那么多线程还会不会提升效率?
在这里插入图片描述
答:不会。并不是任何时候多线程的效率都要比单线程高,当任务量很少的时候,单线程的效率可能会比多线程更高,创建线程本身也会有一定的系统开销,这个开销没有创建进程的开销大,两个线程在CPU上调度也需要一定的时间。

2.Thread 类及常见方法

2.1Thread的常见构造方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用Runnable对象创建线程对象
Thread(String name)创建线程对象并命名
Thread(Runnable target, String name)使用Runnable对象创建线程对象,并命名
public class Demo02_Thread {public static void main(String[] args) {Thread t1 = new Thread(()->{while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("hello thread...");}});t1.start();Thread t2 = new Thread(()->{while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("我是一个有名字的线程...");}}, "我是一个线程");t2.start();}
}

输出结果:
在这里插入图片描述

在这里插入图片描述

可以通过Thread。currentThread().getName()来获取线程名。

public class Demo02_Thread {public static void main(String[] args) {Thread t1 = new Thread(()->{while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName() + "  hello thread...");}});t1.start();Thread t2 = new Thread(()->{while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName() + "  我是一个有名字的线程...");}}, "我是一个线程");t2.start();}
}

输出结果:
在这里插入图片描述

public class Demo02_Thread {public static void main(String[] args) {Thread t2 = new Thread(()->{//获取当前类名String cName = Demo02_Thread.class.getName();//获取当前线程名Thread thread = Thread.currentThread();String tName = thread.getName();//获取当前方法名String fName = Thread.currentThread().getStackTrace()[1].getMethodName();while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("当前类:" + cName + "  当前方法:" + fName + "  当前线程:" + tName);}}, "我是一个线程");t2.start();}
}

输出结果:

当前类:lesson02.Demo02_Thread  当前方法:lambda$main$0  当前线程:我是一个线程
当前类:lesson02.Demo02_Thread  当前方法:lambda$main$0  当前线程:我是一个线程
当前类:lesson02.Demo02_Thread  当前方法:lambda$main$0  当前线程:我是一个线程
......

2.2Thread的几个常见属性

属性获取方法说明
IDgetID()JVM中默认为Thread对象生成的一个编号,是Java层面的,要和操作系统层面的PCB区分开
名称getName()
状态getState()是Java层面定义的线程状态,要和PCB区分开
优先级getPriority()
是否后台线程isDaemo()线程分为前台线程和后台线程,通过这个标识位来区分当前线程是后台还是前台
是否存活isAlive()表示的是系统中PCB是否销毁,与thread对象没啥关系
是否被中断isInterrupted()通过设置一个标志位让线程在执行时判断是否要退出

Thread是Java中的类–>创建Thread对象–>调用start()方法–>JVM调用系统API生成一个PCB–>PCB与Thread对象一一对应

Thread对象与PCB所处的环境不同 ,所以它们的生命周期也不相同。
线程是否存活

public class Demo04_Thread {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{for (int i = 0; i < 5; i++) {System.out.println("hello thread....");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("线程执行完成");});System.out.println("启动之前是否存活:" + thread.isAlive());thread.start();System.out.println("启动之后是否存活:" + thread.isAlive());//等待线程执行完成thread.join();//等待一会,确保PCB已销毁Thread.sleep(1000);System.out.println("启动之后查看线程是否存活:" + thread.isAlive());}
}

输出结果:

启动之前是否存活:false
启动之后是否存活:true
hello thread....
hello thread....
hello thread....
hello thread....
hello thread....
线程执行完成
启动之后查看线程是否存活:false

线程中断

  1. 通过共享的标记来沟通
public class Demo05_Thread {//定义一个标志位static boolean isQuit = false;//lambda表达式里面如果使用局部变量,会触发“变量捕获”,需要把这个变量定义为全局的。public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{while (!isQuit) {System.out.println("hello thread....");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}//线程退出System.out.println("线程退出");});//启动线程thread.start();//休眠5秒Thread.sleep(5000);//修改标志位isQuit = true;}
}

输出结果:
在这里插入图片描述
2. 调用interrupt()方法来通知

public class Demo06_Thread {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{//通过线程对象内部维护的中断标识,判断当前线程是否需要中断while (!Thread.currentThread().isInterrupted()){System.out.println("hello thread...");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("线程已退出");});//启动线程thread.start();//休眠Thread.sleep(5000);//中断线程,发出中断信号thread.interrupt();}
}

输出结果:
在这里插入图片描述
可以看到输出的结果是抛出了一个异常,然后继续往下执行,抛出的异常信息显示的是睡眠中断。

线程中具体的任务是打印一句话,所以线程中的大部分时间是在休眠,也就意味着线程是在休眠的时候中断的,所以就是中断的休眠状态下的线程,而不是执行线程任务的线程。

2.3后台线程和前台线程

public class Demo03_Thread {public static void main(String[] args) {Thread t1 = new Thread(()->{while (true) {System.out.println("hello thread...");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});//设置为后台线程t1.setDaemon(true);t1.start();System.out.println("线程是否存活:" + t1.isAlive());System.out.println("main方法执行完成");}
}

输出结果:
在这里插入图片描述

如果不设置为后台线程呢?
在这里插入图片描述
设置为后台线程之后,main方法执行完成之后整个程序就退出了,子线程也就自动结束了。

如果是前台线程,子线程不会受main方法的影响,会一直运行下去。

创建线程时默认时前台线程。

前台线程可以阻止进程的退出,后台线程不阻止进程的退出。

2.4 中断一个线程

正常执行任务的状态下中断线程

public class Demo07_Thread {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{//通过线程对象内部维护的中断标识,判断当前线程是否需要中断while (!Thread.currentThread().isInterrupted()){System.out.println("hello thread...");}System.out.println("线程已退出");});//启动线程thread.start();//休眠Thread.sleep(5000);//中断线程,发出中断信号thread.interrupt();}
}

输出结果:
在这里插入图片描述
调用thread.interruptO方法时

  1. 如果线程在运行状态,直接中断线程,不会报异常,符合程序预期。
  2. 如果线程在等待状态,就会报一个中断异常,要在异常处理代码块中进行中断逻辑实现。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com