Java多线程全细

Java多线程


对于多线程个人理解



前言

本文将会对于多线程基本概念,线程创建与使用,线程同步,线程通信,JDK5.0新增线程创建方式进行讲解

提示:以下是本篇文章正文内容,下面案例可供参考

一、基本概念

1.程序、进程、线程

程序(program):为了完成特定功能,使用各种编程语言编写的一段静态代码

进程(process):是程序一次执行的过程,或是正在运行的一个程序。是一个动态的过程.进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域。

线程(thread):进程可以细化为线程,可以理解为程序内部的一条执行路径。如果一个进程同一时间并行执行,就是支持多线程的。线程作为调度和执行的单位,每个线程拥有独立的运行站和程序计数器

如果多个线程操作彼此共享的数据时候就会存在安全问题

2.并行与并发

  • 并行:多个CPU同时执行多个任务,在同一个时间段,执行不同的任务。
  • 并发:单核CPU(采取时间片)实现的多线程,在同一个时间段执行相同任务。

3.多线程的优点

1.提高应用的响应
2.提高CPU的利用率,提高性能
3.改善程序结构,将复杂而长的进程分为多个线程,独立运行,便于理解与修改

4.何时需要多线程

  • 程序需要同时执行两个或多个任务
  • 程序需要实现一些需要等待的任务
  • 需要一些后台运行程序时

5.线程的分类

Java线程分为两种:用户线程,守护进程

thread.setDaemon(true)可以将一个用户线程设置为守护进程
注意:如果JVM中都是守护进程,当前JVM将推出

二、线程的创建与使用

1.继承Thread

  1. 继承Thread的类
  2. 重写run方法,写入操作共享数据的代码块
  3. new一个继承类
  4. 调用当前对象的start方法

以下是一个模板:>

public class MyThreadTest01 {
   public staic void main(String[] args){
        MyThread m1 = new MyThread();
        m1.start();
   }
}

class MyThread extends Thread {
   @Ovrride
   public void run(){
      //操作共享数据的代码块
   }
}

在这里插入图片描述

2.实现Runnable接口类

  1. 创建实现Runnabel接口类 重写run方法
  2. new实现类对象
  3. 将实现类对象作为参数传入Thread类对象内
  4. 调用线程类对象的start方法
public class Test01 {
    public static void main(String[] args) {
        MyThread m1 = new MyThread();
        Thread t1 = new Thread(m1);
        t1.start();
    }
}

class MyThread implements Runnable {
    @Override
    public void run(){
        //操作共享数据的代码块
    }
}

在这里插入图片描述

3.实现Runnable接口较比继承Thread的优点

  1. 继承Thread类的方法,由于Java只有单继承,有局限性
  2. 反而Runnable接口实现类,可以进行多继承,能实现更好的扩展
  3. 增强代码的健壮性,解耦操作,代码能够被多个线程共享,代码与数据独立的
  4. 适合多个相同代码的线程去处理共享资源的情况
  5. 线程池只能放入Runnabel和Callable类线程,不能直接放入继承Thread的类

线程的生命周期

线程共分为以下状态:

  1. 新建:new一个线程类创建的线程
  2. 就绪:调用start方法,启动线程处于可被CPU调用的状态
  3. 运行:CPU分配资源,获取执行权,开始运行run方法
  4. 阻塞:CPU从运行状态进入阻塞的状态,等待唤醒
  5. 死亡:正常运行结束死亡/出现异常或Error退出/调用stop方法强行终止
    在这里插入图片描述

Thread类的常用方法

1.void start()

启动线程,并调用对象的run方法

2.run()

线程在调度时执行的操作

3.String getName()

获取当前线程的线程名

4.void setName()

设置当前线程的线程名

5.static Thread currentThread()

返回当前线程的信息,在Thread子类中是this,通常用于主线程和Runnable实现类

6.static void yield()

暂停正在执行的线程,把执行机会给优先级相同或更高的线程
若队列中没有同优先级的下城,忽略此方法

7.join()

当某个线程中调用其它线程的join方法,调用线程被阻塞,直到join方法加入的join线程执行完毕
低优先级的线程也可以获得执行

8.static void sleep(long millis)

使当前执行的线程在指定时间内放弃对CPU控制,使其它线程有机会被执行,时间到后,重排队
会抛出InterruptedException

9.stop()

强制线程生命周期结束,不推荐使用

10.boolean isAlive()

放回boolean 判断当前线程是否还活着

11.thread.setDaemon(true)

可以将一个用户线程设置为守护进程

线程的调度

  1. 高优先级抢占低优先级被CPU调用的执行权,但是存在概率,并非一定
  2. 同优先级线程组成先进先出队列,使用时间片策略
  3. 对于高优先级,使用抢占式策略

线程的优先级等级

  • MAX_PRIORITY 10
  • MIN_PRIORITY 1
  • NORM_PRIORITY 5

调整优先级

  • getPrioity() 返回线程的优先级
  • setPrioity(int newPrioity) 改变线程的优先级

线程创建时继承父线程的优先级
低优先级只是获得调度的概率低,并非是高优先级线程之后调用

线程的同步机制

由于多个线程在操作共享资源时,会由于不安全导致数据的不稳定
会损坏共享数据

同步的方法

synchronized 同步方法/同步代码段

注意:此时的synchronized·定义在方法上出现,隐式定义了同步监视器

  1. 如果是static修饰的静态方法,此时的同步监视器是当前类对象
  2. 如果不是静态方法,则是this,指向当前对象

在这里插入图片描述

注意:同步代码段中synchronized不可包多也不可包少,包多会导致一个线程把整个run方法执行完,包少会导致共享数据操作遗落,也可能会因此引起数据的不完整,不确定性

  1. 此时的this是同步监视器,作为显示定义同步监视器,必须是唯一的对象,否则会导致多个线程执行用的不是同一个锁,也会导致执行结果难以预料
    在这里插入图片描述

ReentrantLock

注意:如果调用了lock方法,需要在需要地方调用unlock方法释放锁

  1. new一个ReentrantLock对象
  2. 在需要同步的地方调用lock和unlock方法
    在这里插入图片描述

synchronized与lock的异同与优先级顺序

相同点:都是解决线程不安全问题
不同点:lock手动开锁和关锁 lock锁只有代码块锁 JVM将花费更小时间来调度线程 性能更好 有更好的扩展性(提供更多的子类) 显示锁 手动释放
synchronized是执行就自动关锁 到执行结束才会开锁 隐式锁 出了作用域 自动释放

线程通信

1.wait notify notifyall

  1. 只能用在同步代码块和段中 wait 阻塞当前线程 直到其它线程调用notify或notifyAll方法进行通知 notify 打开锁
  2. 打开当前线程的等待锁 但是会等到notify线程退出同步块才会释放锁 notifyAll
  3. 全部在该对象上wait的线程通通退出WAITTING状态 优先级 notify会优先释放优先级高的锁的进程

wait和notify操作

wait会立即释放当前对象的锁
notify则不会立即释放当前对象的锁 只有执行完同步代码块 才会
//注意线程通信 线程同步哪些能用
synchronized 同步方法 和 同步代码段
//注意此方法必须是同步监视器发起的 否则会报IllegalMonitorStateException异常

额外补充

run和start的区别

run只会调用当前线程去执行run方法 start则是启动一个新线程去执行run方法

懒汉式和饿汉式的线程安全问题

懒汉式
调用的时候才会创建对象,减少资源开销
线程是不安全的 可能会出现多次调用的new对象不是同一个
饿汉式
提前将对象给创建好了
每次调用 都是返回同一个对象

面试题:sleep和wait异同

相同:执行此方法,都可以使当前线程进入阻塞状态
不同:1)两个方法声明的位置不同,Thread类中声明sleep,Object类中声明wait
2)调用要求不同,sleep方法可以在任何需要的环境调用,wait必须使用在同步代码中或同步方法内
3)关于释放同步监视器,如果两个都使用在同步代码块或同步方法,wait会释放锁,sleep不会释放

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值