java多线程

进程是程序的一次动态执行过程,拥有独立的内存空间;线程是进程中的执行流程,是操作系统调度的最小单位。Java中,可以通过继承Thread类或实现Runnable接口创建线程。线程同步用于多线程访问同一资源时的控制,包括synchronized关键字和同步代码块。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 概述

程序:程序是对数据描述与操作的代码的集合,如暴风语音应用程序

进程:是程序的一次动态执行过程,它对应了从代码加载,执行至执行完毕的一个完整过程。

线程:线程是进程中的一个执行流程,一个进程中可以运行多个线程(线程是进程中执行运算的最小单位)

  1. 进程

操作系统进程:系统进程(系统建立);用户进程(用户建立)

特点:

  1. 进程是系统运行程序的基本单位
  2. 每个进程都有自己独立的一块内存空间,一组系统资源
  3. 每一个进程的内部数据和状态都是完全独立的

动态性:执行过程,动态产生,动态消亡

并发性:任何进程可以一起执行

独立性:进程是一个能独立运行的进本单位,同时也是系统分配资源和调度的独立单位

异步性:进程之间相互制约,是进程具有执行的间断性,即进程按各自独立的不可预知的速度向前推进

  1. 线程

线程是进程中执行的运算的最小单位,可完成一个独立的顺序控制流程。每个进程中,必须至少建立一个线程

(主线程),来作为这个程序运行的入口点。如果在一个进程中同时运行了多个线程,用来完成不同的工作。则称为”多线程”;多个线程并不是同时执行的,是因为不同线程之间切换的时间非常短

多线程的好处

  1. 充分利用CPU资源
  2. 简化编译模型
  3. 带来良好的用户体验
  1. 进程与线程的区别

进程和线程的主要差别在于他们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,

在保护模式下,不会对其他进程产生影响,而线程只是一个进程中的不同执行路径,线程有自己的堆栈和局部变量,但线程之间没有独立的地址空间,一个线程死掉,就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源大,效率差,但是对于一些要求同时进行并且又要共享一些变量的并发操作,只能用线程,不能用进程

  1. Thread类常用用法

Thread:分配新的线程对象

Thread(Runnable   target):配新的线程对象,target为run方法被调用的对象

Thread(Runnable   target,String  name):配新的线程对象,target为run方法被调用的对象,name为新线程的名称:

Void  run():执行任务操作的方法

Void  statrt():使该线程开始执行,Java虚拟机调用该线程的run()方法、

Void  sleep(long millis):在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)

String  getName():返回线程的名称

Void  setName():更改线程名称

Int   getPriority():返回线程的优先级

Void  setPriority(int newPriority):更改线程的优先级

Static  Thread  currentThread():返回当前正在执行的线程对象的引用

Boolean  isAlive():测试线程是否处于活动状态

Void  join():等待该线程中止

Void  interrupt():中断线程

Void yield():暂停当前正在执行的线程对象,并执行其他线程

  1. Java主线程

在Java程序启动时,一个线程立刻运行,该线程通常称为程序的主线程

Java的main方法是主线程的入口,每个进程都至少有一个主线程。它是程序开始时就执行的

尽管主线程在程序启动时自动创建,但它可以由一个Thread对象控制。

例子:

 Thread thread=Thread.currentThread();

 System.out.println("当前的线程是:"+thread.getName());

 thread.setName("ljl");

 System.out.println("当前的线程是:"+thread.getName());

作用:

(1)产生其他子线程的线程

(2)通常他必须最后完成执行,因为它执行各种关闭动作

使用:

  1. 定义一个线程,同时指明这个线程所要执行的代码,即期望完成的功能
  2. 创建线程对象
  3. 启动线程
  4. 中止线程

7.实现线程的两种方式

(1)继承Thread类创建线程

(2)实现Runnable接口创建线程

8.继承Thread类创建线程

使用此方法创建线程类,此线程类需要继承Thread类并重写Thread类的run()方法,因为Thread类的run()

方法是线程要执行操作任务的方法,所以线程要执行的操作代码都需要写在run()方法中,并通过调用

start()方法启动线程后调用

步骤:

  1. 定义要使用的线程类,继承Thread类
  2. 重写run方法,在run方法中编写代码
  3. 创建线程对象,调用start()方法启动线程

在创建线程未指定线程名的时候,自定义线程默认名为”Thread'-”加序号,序号为从0开始的整数

已经启动的线程的对象不能再次调用start()方法,否则会抛出IllegalThreadStateException异常

例子:

public  class  MyThread

{

public void run(){

//代码

}

}

public  class  test()

{

pulic  static  void  mian(String[] arg)

{

 MyThread  mythread=new MyThread ();

Mythread.start();

}

}

  1. 线程实例调用start()方法和直接调用run()方法

(1)用start()方法来启动线程是实现了多线程,通过调用Thread类的start()方法来启动一个线程,这时此程序就处于就绪可运行状态,但是并没有运行,一旦得到cpu时间片,就开始执行运行run()方法。但要注意的是,此时需要等待run()方法执行完毕,即可继续执行下面的代码

(2)直接调用run()方法并没有实现多线程,run()方法只是类的一个普通方法而已,如果直接调用run()方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后菜可以继续执行下面的代码

注意:多个线程对象调用start()方法启动后,各自执行run()方法中的代码,相当于每个线程有自己的

独立的执行路径,多个分支相互不影响,并行执行,但由于CPU在一个时间点只能执行一个线程,因此多个 线程是交替执行的,获得CPU时间片的线程即刻执行,当前时间片执行完毕后,CPU就会获得下一个时间片的线程。分配的时间片长度不是完全一致的,可多可少,因此每次运行结果有所不同,总之是轮换交替执行的

结论:

start():启动线程   run():调用实例方法

  1. 实现Runnable接口创建线程(解决Java单继承)

Runnable接口定义在java.lang包中,其中声明了一个抽象方法run(),即public  void  run()。一个类

可以通过实现Runnable接口并实现其run()方法完成线程的所有的所有活动,已实现run()方法称为该线程对象的线程体。任何实现Runnable接口的对象都可以作为线程的目标对象。

步骤:

  1. 定义MyRunnable类实现接口Runnable接口,并实现run()方法,在run()方法中编写代码
  2. 创建MyRunnable类对象myRunnable
  3. 创建一个Thread类的对象myThread,将myRunnable对象作为参数传入
  4. 调用myThread对象的start()方法启动线程

代码:

Public  class  MyRunnable  implements  Runnable

{

Public void run()

{

}

}

  1. MyRunnable myRunnable=new MyRunnable();

Thread myThread=new Thread(myRunnable);

MyRunnable.start();

(2)Thread myThread=new Thread(new MyRunnable());

MyRunnable.start();

  1. 两种创建线程方式的应用
  1. 继承Thread类的方式,编写简单,可以直接操作线程,适用于单继承的情况
  2. 当一个线程继承继承了另一个类时,就只能实现Runnable接口的方式来创建线程,而且这种方式还可以实现多个线程之间的资源共享。
  1. 线程的状态
  1. 创建状态

在程序中创建了一个线程对象后,新的线程对象就处于创建状态。此时,它已经获得了相应的资源,但还没有处于可运行的状态,这时可以通过Thread类的方法来设置线程对象的属性

  1. 就绪状态

线程创建之后,就可以通过调用start()方法启动线程,即进入就绪状态。此时线程将进入线程队列排队

等待CPU资源,这表明它已经具备了运行的条件,在未获得CPU资源时,仍不能真正执行

  1. 运行状态

当就绪状态的线程获得CPU资源时,即可转入运行状态,执行run()方法。对只有一个cpu的计算机而言

,任何时刻只能有一个处于运行状态的线程占用cpu,即获得cpu资源

  1. 阻塞状态

一个正在运行的线程因某种原因不能继续运行时,进入阻塞状态,而处于这种状态的线程在得到一个特定的事件之后转会可运行状态

可能使线程成为阻塞状态的条件是:

  1. 由于线程的优先级比较低,因此它不能获得cpu资源
  2. 使用sleep()方法使线程休眠
  3. 通过调用wait()方法,使线程等待
  4. 通过调用yield()方法,使线程让出cpu控制权
  5. 线程由于等待一个文件,i/o事件被阻塞

(5)死亡状态

一个线程的run()方法运行完毕后,线程则进入死亡状态,处于死亡状态的线程不具有继续运行的能力

  1. 线程的调度

按照特定机制为多个线程分配cpu的使用权

  1. 线程的优先级

每个线程会自动获得一个线程优先级(5),优先级的高低反应线程的重要或紧急程度。那么此刻,一般情况下优先级高的线程获得CPU资源的概率较大,但这个结果不是绝对的线程的优先级用1-10来表示,1.表示优先级最低,10表示优先级最高,默认值是5,这些优先级

对应一个Thread类的公用静态常量,例如

  1. public  static final  int NORM_PRIORTY=5;
  2. public  static final  int MAX_PRIORTY=10;
  3. public  static final  int MIN_PRIORTY=0;

每个线程的优先级介于Thread.MIN_PRIORTY和Thread.MAX_PRIORTY之间,线程的优先级可以通过

getPriority()方法获取,setPriority(int grade)方法来更改,后者的参数表示要设置的优先级,它必须是 1-10的整数。

例如:

线程对象.setPriority(MAX_PRIORTY);

线程对象.setPriority(4);

  1. 线程的休眠

在程序中允许一个线程进行暂时休眠,直接使用Thread.sleep()方法即可实现线程的休眠。

Public  satic  void  sleep(long  millis)

Thread.sleep();

sleep()会让当前线程休眠(停止执行)millis毫秒,线程由运行中的状态进入不可运行的状态。

睡眠时间过后线程会再次进入可运行状态。调用sleep()方法需处理InterruptedException异常

  1. 线程的强制运行

Join()方法使当前线程暂停执行,等待调用该方法的线程执行结束后在继续执行本线程。它有

三个重载方法。

public final void join()

public final void join(long mills)

public final void join(long mills,int nanos)

与sleep()方法一样,调用join()方法需要处理nterruptedException异常。

  1. 线程的礼让

yield()方法可暂停当前线程执行,允许其他具有相同优先级的线程获得运行机会,该线程仍处于就绪状态,不转为阻塞状态,此时系统选择其他相同或更高优先级线程执行,若无其他相同或更高优先级线程,则该线程继续执行

public  static  void yield()

Thread.yield();

使用yield()的线程礼让只是提供一种可能,但是不能保证一定会实现礼让,因为礼让的线程处于就绪状态,还有可能被线程处于就绪状态,还有可能被线程调度程序再次选中

  1. 线程同步

当两个或多个线程需要访问统一资源时,需要以某种顺序来确保该资源某一时刻只能被一个线程使用

这就称为线程同步

  1. 同步方法:

访问修饰符  synchronized  返回类型 方法名(参数列表){//代码}

synchronized 访问修饰符  返回类型 方法名(参数列表){//代码}

缺陷:如果将一个运行时间比较长的方法声明成 synchronized 将会影响效率

  1. 同步代码块

Synchronized(syncObject){//代码}

在同步代码块时必须指定一个需要同步的对象,但一般都将当前对象(this)设置成同步对象

注意:

使用线程同步时

  1. 当多个并发线程访问同一个对象object的Synchronized(this)同步代码块时,同一时刻只能有一个线程得到执行,其他线程必须等待当前线程执行完毕之后才能执行该代码块
  2. 当一个线程访问object的一个Synchronized(this)同步代码块时,其他线程对object中所有其他

Synchronized(this)同步代码块的访问将被阻塞。即该线程获得这个object的对象锁,其他线程对该object对象所有同步代码部分的访问都将被阻塞

(3)当一个线程访问的object的一个synchronized(this)同步代码块时,其他线程仍可以访问该object的非

synchronized(this)同步代码块

  1. 线程安全的类型

所在的进程中有多个线程,而当这些线程同时运行时,每次结果和单线程运行的结果是一样的,而其他变量的值和预期是一样的,就是线程安全的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值