首页 > 编程语言 > 详细

Java多线程

时间:2019-12-26 17:56:35      阅读:79      评论:0      收藏:0      [点我收藏+]

概念

进程

进程是程序的一次动态执行过程

线程

比进程更小的执行单位,是进程中的一个单独的顺序控制流。

它是进程中的独立运行的子任务

线程拥有共享的进程资源

Java的多线程

并发

Java虚拟机允许应用程序同时执行多个执行线程,这在Java种叫做并发。

创建线程的方法

  • 通过继承Thread创建线程
  • 通过实现Runnable接口来创建线程
  • 通过实现Callable接口和Future接口来间接创建线程

1.继承Thread创建线程

构造方法

技术分享图片

常用方法

技术分享图片

注意

  • join() 是调用A线程来帮助完成任务
  • join(long millis)参数的意思是设置一个等待时间,超过这个时间就不再等待。

  • 通过start()启动线程后,系统自动调run()方法来执行线程

2.实现Runnable接口创建线程

因为java只能继承一个类,所以通过继承Thread的方法创建线程的方法不能再继承其他类,不适合资源共享

所以可以用到Runnable接口来创建线程,并且可以继承其他线程。

  • 通过覆盖接口Runnable接口run()方法来创建线程体。

  • 需要通过Tread包装Runnable实现对象来创建线程,因为除了Thead其他方法种没有start()方法,没法启动线程。

3.实现Callable和Future创建线程

前两个方法都不能获取线程执行结果,JDK1.5以后就可以通过这两个接口来获取线程返回的结果

Callable泛型接口

接口中只有一个call()方法 ,他是线程执行体,具有返回值。

Future泛型接口

作用

表示异步任务,用于对具体的Runnable或者Callable任务执行结果进行中断,查询是否完成,获取结果。

方法

技术分享图片

FutureTask类

它是RunnableFuture<V>泛型接口的实现类,而RunnableFuture<V>RunnableFuture接口的子接口

所以这个类可以作为Runnable被线程执行,同时也可以作为Future得到Callable的返回值

构造方法
方法 作用
FutureTask(Callable<T>callable) 在运行时执行给定的Callable
FutureTask(Runnable runnable,V result) 在运行时执行给定的Runnable,并安排get将在成功完成以后返回给定结果
  • 通过包装Callable来创建对象
  • 需要通过Thread包装来执行线程
  • 可以通过FutureTask对象的get()来获取call()的执行结果

主线程

java程序至少有一个主线程,线程名为main,系统会为它自动分配ID,优先级为5,它不需要run()方法

线程的执行顺序

线程随机启动,取决于操作系统,不取决于代码start()顺序。

线程的状态及控制

线程的状态

java中将线程分为6个状态,状态封装在ThreadState枚举中,这代表虚拟机的状态

线程在操作系统中执行的状态,线程可以分为7种状态

  • 新建态(NEW)

    创建线程但没有调用start()

  • 就绪态也可称为可运行态(RUNABLE)

    调用start()方法以后

  • 运行态

    分配到CPU之后的状态

  • 等待状态

    调用wait()方法线程就进入等待状态

    • 需要调用notify()或者notifyAll()才能被唤醒
    • notifyAll()能唤醒所有线程
  • 休眠状态

    调用sleep()方法以后

  • 阻塞状态

    线程在运行状态下发出输入/输出请求

  • 死亡状态

    run()方法执行玩完毕

线程控制

  1. 线程启动--start()方法

  2. 线程休眠--sleep()方法

  3. 线程让步--yield()方法

    让当前线程放弃当前的cpu资源,让给其他任务去执行,但是放弃的时间不确定。

  4. 线程等待--wait()方法

    常用于线程同步

  5. 线程唤醒--notify()notifyAll()方法

  6. 暂停线程

    使用suspend()来暂停线程,使用resume()方法来恢复线程,但是方法不安全,JDK8以后停用

  7. 线程加入--join()方法

    • 使它调用的线程结束时,join()所在的线程再继续。
    • 如果再主方法种使用该方法,那么主方法会最后执行
  8. 线程状态检查--isAlive()方法

  9. 结束线程

    Thread.stop()方法,但是不推荐用,已经被作废

    以下有3种结束正在运行的线程方法

    1. fs
    2. dsa
    3. 中断线程,使用interrupt()来中断

线程优先级

优先级的等级

优先级的修改

方法 方法
public final void setPriority(int new Priority) 设置优先级
获取优先级

守护线程

守护线程的判断

public final boolean isDaemon()

设置守护线程

public final void setDaemon(boolean on)

  • 如果ontrue那么设置为守护线程

  • 如果onfalse那么取消设置守护线程

线程组

可以把一组线程作为单个对象进行统一处理和维护,可以对所有线程进行同时操作

构造方法

方法 作用
public ThreadGroup(String name) 创建名为name的线程组对象
public ThreadGroup(ThreadGroup parent,String name) 创建具有给定父组和名称的线程组对象

常用方法

技术分享图片

线程同步

加入同步锁来避免在线程调用没有结束之前再被其他线程调用,保证数据准确性和唯一性

同步块

synchronized关键字写在某段代码块之前,可以让代码块加上线程锁

格式
synchronized(object){
    //代码块
}

object是对象锁,如果在类中代码段进行同步,可以使用this

同步方法

使用synchronized关键字修饰方法,内置锁(java每个对象都有一个)可以保护整个方法。

内置锁默认为this

格式
[修饰符]synchronized<返回类型>方法名([参数列表]){
    //方法体
}

同步锁

Lock接口
方法

技术分享图片

ReentrantLock实现类

他是Lock接口的实现类,继承并增加了方法

  • 创建锁的时候创建为final对象
构造函数
增加方法

技术分享图片

步骤
  1. 在类中创建锁对象
  2. 在代码前对锁对象执行lock()方法
  3. finally子句中对锁对象执行unlock()方法

线程通信

线程之间可以共享资源和数据,这需要Java中的一些机制来保证线程之间的协调运行

等待唤醒模式通信(wait-notify)

在同步机制下,线程使用了wait()以后就放弃运行资格,处于等待状态。通过调用nitify()来唤指定等待线程(并不能确定唤醒哪个线程,这个由操作系统决定),通过这两个方法实现了线程之间的通信

说明
  1. 这种通信模式用来同步机制中,因为只有同步才有锁。
  2. 使用时必须标识他们锁操作线程持有的锁。
例子(生产者-消费者)

技术分享图片

加锁机制下的通信模式(Lock+Condition)

JDK1.5之后Condition是一个接口,将waitnotifynotifyAll替换成了Condition接口对象,用Lock代替了synchronized方法和语句的使用。

通过Lock对象调用newCondition()方法获得Condition对象,通过Condition对象的await()、signal()、signalAll()方法来实现线程通信

获取Condition对象

Condition 对象名=Lock对象.newCondition();

Condition接口中的方法

技术分享图片

  • await()/signal()必须在lock.lock()lock.unlock()之间
  • ConditionObjectwait/notify的对应关系
    • await()---wait()
    • signal()---notify()
    • signalAll()---notifyAll()
  • 一个Lock对象上可以有多个Condition对象
线程通信的理解
  • 每个对象都有一个monitor任意对象都有,可以理解为一把锁,所以可以任意创造一个对象个两个对象通信。
  • 如果想要调用这个对象的wait()方法,必须获得这把锁。
  • 如果调用这个对象的wait()方法,那么当前线程就会让出这个对象的monitor,然后进入等待状态。
  • notify()可以唤醒一个正在等待monitor的线程,但是只能给一个线程,这个由操作系统决定。
  • notifyAll()可以唤醒所有等待monitor的线程,但也只有一个线程能够得到对象的monitor,也是由操作系统决定的
  • 唤醒不能立刻获得对象的monitor,只有线程退出同步块或者取消了lock才能得到锁
  • 多个线程通信可能发生假死,比如生产者唤醒生产者,消费者唤醒消费者,这时候将唤醒改为notifyAll()即可

Java多线程

原文:https://www.cnblogs.com/JMWan233/p/12102606.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!