您的位置 首页 java

看一下吧,自己对线程以及锁的概念和原理了解是否正确

目录

1、线程 Thread 生命周期 & 基本使用

2、锁

3、Object 的wait 和 notify 方法

进程是资源分配的最小单元,线程是程序执行的最小单元,通常在一个进程中包含了多个线程。单个CPU在一个时刻只能把时间片分配给一个线程去执行。线程的整个生命周期包含了多个状态,未运行的初始状态,启动后未获取CPU时间片的待运行状态,任务执行完成后的消亡态,和线程紧密工作的锁又是如何控制线程的进入和退出的,接下来就学习和了解下Java的线程和锁的基本特点。

1、线程Thread 生命周期 & 基本使用

线程类中包含了多种状态,可通过getState方法获取到State枚举类信息

public enum State {
 NEW, 
 RUNNABLE,
 BLOCKED, 
 WAITING, 
 TIMED_WAITING, 
 TERMINATED;
}
 

NEW :线程还未开始的状态

RUNNABLE :在JVM中是运行的状态,但真正执行需要操作系统分配必须的资源才可运行

BLOCKED :等待Monitor Lock(监视器锁) 被阻塞导致,例如 synchronized

WAITING :因为非时间因素导致线程等待的,例如Object.wait()、Thread.join()、LockSupport.park()等

TIMED_WAITING :因为时间因素导致线程等待的,例如Thread.sleep()、Object.wait(time)、Thread.join(time)等

TERMINATED :线程执行完成,消亡状态了

实际状态流转中每一种状态的变更都是有着其具体的原因,例如Object.wait()方法执行后,线程一方面会自行暂停,另一方面会进入到当前对象的一个等待集合中,等待超时、notify唤醒又或者中断引发的中断时间而离开等待集合,如下图可能可以更好的说明线程的流转关系。

具体方法以及相关关键字在后面再做介绍,先了解下线程如何使用的,线程的使用有两种方法, 继承Thread 类 实现Runnable 接口 ,都是重写run方法,Runnable更多的可以看做是一个Task任务,任务可以交由任何可执行的线程去执行,但是继承Thread的在一创建时就已经固定了,没有足够的灵活性, 推荐使用Runnable

用java8最新的lambda表达式也可以很方便的写成 Runnable runnable = () -> {/* run方法运行实体*/} ,然后直接交给Thread执行即可。

请勿直接调用线程的run方法,那样无法创建新线程执行。调用start方法会由native方法创建新线程然后调用run方法

2、锁

现实中我们也大量的应用到锁,为了防止家里的财产被盗,离开家门时会锁门,日常用的电脑为了确保资料安全也会给自己的账户设置个密码锁,不过这也意味着我们日常外出需要带着钥匙,记住密码,要不然会导致很多不必要的麻烦。和实际生活一样,Java中的锁也是为了保证数据(服务)安全,也会对服务的性能、吞吐量等造成影响。

那锁是什么呢?

  • Java中的一切都是对象,锁也不例外,这个被锁的对象只能由锁保护资源所在的线程去访问
  • 锁可以控制对数据访问的先后顺序(强行串行化)
  • 锁可以控制对数据是否拥有访问权
  • 锁可以控制服务的活跃性问题
  • 锁也可以抑制指令重排(降低效率)

常见的锁种类

  1. synchronized:Java原生语义支持的,内置锁,可重入,悲观的,在JDK1.5以后synchronized在不同情况下从 无锁->偏向锁->轻量级所->重量级锁的转变。
  2. ReentrantLock:基于AQS开发的可重入锁,有公平和非公平之分,也可以感知到中断
  3. CountDownLatch:基于AQS开发的锁,也叫计时器锁,当计数器减为0后,就可以执行其他任务了,不可重置
  4. CyclicBarrier:同样是基于AQS开发的锁,也叫栅栏锁,有换代的操作,可重置(想象成多个栅栏一般)
  5. Condition:条件锁,用在阻塞队列中,可控制消费者和生产者的读取进度
  6. ReentrantReadWriteLock:读写锁,读和写拆开,可以极大的提高读多写少的场景下的性能

对象锁对应的监视器锁结构如下图所示

本图来自:

  1. Special Room:当前运行的线程所存储的地方
  2. Entry Set: 所有需要获取当前锁的线程存储的地方
  3. Wait Set:所有被调用wait方法的线程存储的地方

3、Object 的wait 和 notify 方法

wait、notify方法是Object类的final native方法,不能被重写,而且必须有同步器synchronize的辅助才可以使用(这个是JVM规定的)

 synchronized (OBJ) {
 try {
 while (count <=0) {
 // 当前线程暂停执行
 OBJ.wait();
 }
 ......
 // 具体的任务
 OBJ.notify();
 // 唤醒其他线程工作
 } catch (InterruptedException e1) {
 e1.printStackTrace();
 // 由wait方法触发的中断
 }
 }
 

wait方法是用来释放锁并且暂停服务的,从上面的线程流转图也可以看出来,对象调用wait()方法后, 当前执行的线程会进入到当前对象的监视器对象的Wait Set区域内 ,执行notify方法,会从Wait Set集合中随便挑选一个然后唤醒操作进入到Entry Set集合中,后续的具体执行还得看具体的资源分配等情况,notifyAll方法可以唤醒所有等待的线程,至于那一个现在真正的执行同样也是无法感知的。

文章来源:智云一二三科技

文章标题:看一下吧,自己对线程以及锁的概念和原理了解是否正确

文章地址:https://www.zhihuclub.com/194127.shtml

关于作者: 智云科技

热门文章

网站地图