线程及同步锁

  • 1. 进程
  • 1.1 进程的概念
  • 1.2 进程的特点
  • 2 线程
  • 2.1 线程的概念
  • 2.2 进程和线程的区别
  • 2.3 进程和线程的关系
  • 2.4 线程状态
  • 2.5 多线程创建
  • 2.5.1 继承Thread
  • 2.5.2 实现Runnable接口
  • 2.5.3 创建多线程方法的比较
  • 2.5 线程的方法
  • 2.5.1 阻塞线程的方法
  • 2.5.1 停止线程的方法
  • 2.5.3 线程的常用方法
  • 2.6 并行和并发的区别
  • 2.7 sleep()和wait()有什么区别?
  • 3 同步锁
  • 3.1 多线程的数据访问冲突
  • 3.2 同步锁的原理
  • 3.3 实现同步的方法
  • 3.3.1 使用同步代码块
  • 3.3.2 使用同步方法
  • 3.4 同步和异步的区别
  • 3.5 判断,我的资源有没有多线程并发的安全隐患


1. 进程

1.1 进程的概念

是程序在执行过程中分配和管理资源的基本单位,每一个进程都有一个自己的地址空间,至少有 5 种基本状态,它们是:初始态,就绪状态,执行态,等待状态,终止状态。

1.2 进程的特点

  • 独立性:进程是系统中独立存在的实体,它可以拥有自己的独立的资源,每一个进程都拥有自己私有的地址空间。在没有经过进程本身允许的情况下,一个用户进程不可以直接访问其他进程的地址空间。
  • 动态性:进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。在进程中加入了时间的概念,进程具有自己的生命周期和各种不同的状态,这些概念在程序中都是不具备的。
  • 并发性:多个进程可以在单个处理器上并发执行,多个进程之间不会互相影响。

2 线程

2.1 线程的概念

线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个进程可以开启多个线程。

2.2 进程和线程的区别

  • 进程是操作系统资源分配的基本单位
  • 线程是任务调度和执行的基本单位

2.3 进程和线程的关系

java进程close_wait Java进程锁_多线程

  • 一个进程中可以有多个线程
  • 每个进程有自己独立的内存,每个线程共享一个进程中的内存,每个线程又有自己独立的内存。

2.4 线程状态

  • 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
  • 就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
  • 运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
  • 阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态;
    根据阻塞产生的原因不同,阻塞状态又可以分为三种:
    等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态,JVM会把该线程放入等待队列(waitting queue)中;
    同步阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态,JVM会把该线程放入锁池(lock pool)中;
    其他阻塞:通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
  • 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

2.5 多线程创建

Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例。

  • 启动线程的唯一方法就是通过Thread类的start()实例方法
  • Start()方法是一个native方法,它将通知底层操作系统,最终由操作系统启动一个新线程,操作系统将执行run()方法。
  • 通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。
  • start()方法只是通知操作系统线程就绪,具体什么时间执行,操作系统来决定,JVM已经控制不了了。

2.5.1 继承Thread

  • 定义 Thread 的子类
  • 重写 run() 方法
  • 在 run() 方法中的代码,是与其他代码并行执行的代码
  • 线程启动后,自动自动执行 run() 方法

2.5.2 实现Runnable接口

如果自己的类已经extends另一个类,就无法多继承,此时,可以实现一个Runnable接口

  • 定义Runnable子类
  • 实现run() 方法
  • 把Runnable 对象,放入 Thread 线程对象启动
  • 线程启动后,执行 Runnable 对象的 run() 方法

2.5.3 创建多线程方法的比较

java进程close_wait Java进程锁_java进程close_wait_02

2.5 线程的方法

2.5.1 阻塞线程的方法

  • Object.wait()
  • Thread.sleep(毫秒值)
    当前线程暂停指定的毫秒时长
  • Thread.join()
    当前线程,等待被调用的线程结束
    在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。

2.5.1 停止线程的方法

  • 正常退出
    当线程中run()或者call()按照逻辑流程正常的执行结束了,线程也就自然停止了
  • stop暴力停止
    直接在程序中使用thread.stop(),线程会马上停止,但是可能导致数据不同步,或者资源得不到回收的问题而且stop已经标注为作废方法,所以使用一定要慎重。
  • interrupt()异常法
    打断一个线程的暂停状态,被打断的线程出现InterruptedException
    线程处于阻塞状态配合interrupt()都使线程停止,而且停止的方式都是通过抛异常方式

2.5.3 线程的常用方法

  • Thread.currentThread()
    获得正在执行这行代码的线程对象
  • Thread.yield()
    让步,当前线程放弃时间片,让出cpu资源,线程进入就绪状态
    让自己或者其它的线程运行,注意是让自己或者其他线程运行,并不是单纯的让给其他线程
  • getName(),setName()
  • start()
  • getPriority(), setPriority()
    优先级,1到10,默认5
    MIN_PRIORITY最低优先级1;NORM_PRIORITY普通优先级5;MAX_PRIORITY最高优先级10

2.6 并行和并发的区别

  • 并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行。所以无论从微观还是从宏观来看,二者都是一起执行的;
  • 并发(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行

2.7 sleep()和wait()有什么区别?

  1. Thread类的方法:sleep(),yield()等
    Object的方法:wait()和notify()等
  2. 每个对象都有一个锁来控制同步访问。Synchronized关键字可以和对象的锁交互,来实现线程的同步。
    sleep方法没有释放锁,
    wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
  3. wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
  4. sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常

3 同步锁

3.1 多线程的数据访问冲突

多个线程,共享访问数据
一个线程访问到修改的一半的数据,称为脏数据

3.2 同步锁的原理

用一个对象作为一把锁,给代码上锁,一个线程访问锁代码时,其他线程只能等待锁释放才能进来

3.3 实现同步的方法

3.3.1 使用同步代码块

锁的代码块,
需要指定锁对象,可以是任意对象,但是必须是同一个对象

synchronized(锁对象){ 有安全隐患的代码 }

3.3.2 使用同步方法

使用同步方法
使用的锁对象是this

synchronized public void eat(){ 有安全隐患的代码}

3.4 同步和异步的区别

  • 同步是指同一时刻只能有一个人操作数据,别人只能排队等待。牺牲了效率,提高了安全。
  • 异步是指同一时刻没人排队,大家一起上一起抢。提高了效率,牺牲了安全。

3.5 判断,我的资源有没有多线程并发的安全隐患

在多线程的场景下 + 共享资源,被多条语句操作 >=2