Java进程与线程、多线程特性、实现方式、start和run、wait和sleep、线程生命周期、Synchronized底层实现原理、锁是什么?如何确定对象的锁?、线程控制

1 进程和线程的区别

  • 进程是资源分配的最小单位,线程是任务调度和执行的基本单位
  • 进程有独立的地址空间,一个进程崩溃,不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。
  • 线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。

2 多线程特性

  1. 原子性
  2. 可见性
  3. 有序性
  • 一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行,这就是原子性操作。
  • 可见性指当一个线程修改了共享变量时,其他线程能够立即得知修改。volatile,synchronized,final都能保证可见性。
  • 程序执行的顺序按照代码的先后顺序执行。

3 Java实现多线程的方式

  1. 继承Thread类实现多线程
  2. 实现Runnable接口实现多线程
  3. 实现Callable接口通过FutureTask包装器来创建Thread线程
  4. 使用线程池接口ExecutorService结合Callable、Future实现有返回结果的线程

4 启动线程方法start()和run()有什么区别?

  • start()方法:用来启动线程,实现了多线程的运行,通过调用Tread类的start方法来启动一个线程,这时此线程处于就绪态,没有运行,当此条线程得到了cpu的时间片,就开始执行run方法,这里的run方法称为线程体,他包含了要执行这个线程的内容,run方法运行结束,线程终止。
  • run()方法就是一个普通的方法,如果直接调用run方法,他仅仅在主线程这条线程中执行。程序仍然顺序执行,执行完run方法体才会执行下面的代码,不会有多线程的效果。

5 线程中的wait()和sleep()方法有什么区别?

  1. 原理不同
      sleep()方法是Thread类的静态方法,是线程用来控制自身流程的,他会使此线程暂停执行一段时间,而把执行机会让给其他线程,等到计时时间一到,此线程会自动苏醒。而wait()方法是object类的方法,用于线程间通信,这个方法会使当前拥有该对象锁的进程等待,直到其他线程调用notify()方法或者notifyAll()时才醒来,不过开发人员也可以给他指定一个时间,自动醒来。
  2. 对锁的处理机制不同
      由于sleep()方法的主要作用是让线程暂停执行一段时间,时间一到则自动恢复,不涉及线程间的通信,因此,调用sleep()方法并不会释放锁。而wait()方法则不同,当调用wait()方法后,线程会释放掉他所占用的锁,从而使线程所在对象中的其他synchronized数据可以被其他线程使用。
  3. 使用区域不同
      wait()方法必须放在同步控制方法和同步代码块中使用,sleep()方法则可以放在任何地方使用。sleep()方法必须捕获异常,而wait()、notify()、notifyAll()不需要捕获异常。在sleep的过程中,有可能被其他对象调用他的interrupt(),产生InterruptedException。由于sleep不会释放锁标志,容易导致死锁问题的发生,因此一般情况下,推荐使用wait()方法。

6 线程生命周期

新建,就绪,运行,阻塞以及销毁

  1. 新建:就是刚使用new方法,new出来的线程;
  2. 就绪:就是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行;
  3. 运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run方法定义了线程的操作和功能;
  4. 阻塞:在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态,比如sleep()、wait()之后线程就处于了阻塞状态,这个时候需要其他机制将处于阻塞状态的线程唤醒,比如调用notify或者notifyAll()方法。唤醒的线程不会立刻执行run方法,它们要再次等待CPU分配资源进入运行状态;
  5. 销毁:如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源;
    在这里插入图片描述

7 多线程同步方法

Synchronized 关键字,Lock 锁实现,分布式锁等

8 Synchronized底层实现原理

  • Java 对象底层都关联一个的 monitor,使用 synchronized 时 JVM 会根据使用环境找到对象的monitor,根据 monitor 的状态进行加解锁的判断。如果成功加锁就成为该 monitor 的唯一持有者,monitor 在被释放前不能再被其他线程获取。
  • synchronized在JVM编译后会产生monitorenter 和 monitorexit 这两个字节码指令,获取和释放monitor。这两个字节码指令都需要一个引用类型的参数指明要锁定和解锁的对象,对于同步普通方法,锁是当前实例对象;对于静态同步方法,锁是当前类的 Class 对象;对于同步方法块,锁是synchronized 括号里的对象。
  • 执行 monitorenter 指令时,首先尝试获取对象锁。如果这个对象没有被锁定,或当前线程已经持有锁,就把锁的计数器加 1,执行 monitorexit 指令时会将锁计数器减 1。一旦计数器为 0 锁随即就被释放。

9 锁是什么?如何确定对象的锁?

“锁”的本质其实是 monitorenter 和 monitorexit 字节码指令的一个 Reference 类型的参数,即要锁定和解锁的对象。


确定方法:

  • 如果 Synchronized 明确指定了锁对象,比如 Synchronized(变量名)、Synchronized(this) 等,说明加解锁对象为该对象。
  • 如果没有明确指定:
    若 Synchronized 修饰的方法为非静态方法,表示此方法对应的对象为锁对象;若 Synchronized 修饰的方法为静态方法,则表示此方法对应的类对象为锁对象。

10 线程控制

join等待阻塞
wait/notify使线程锁定阻塞
sleep
yield
setDaemon

  • join等待阻塞:让一个线程等待另一个线程完成才继续执行。如A线程线程执行体中调用B线程的join()方法,则A线程被阻塞,知道B线程执行完为止,A才能得以继续执行。
  • wait() 和 notify()锁阻塞:方法的调用需要调用的方法有一个锁对象,主要用于进行不同线程之间的同步协作,常见的有生产者消费者模型。
  • sleep() 其他类型阻塞:让当前的正在执行的线程暂停指定的时间,并进入阻塞状态。直接使用 Thread.sleep(long millionSeconds) 就可以了
  • yield() 线程让步:将线程从运行状态转换为就绪状态。
    当某个线程调用 yiled() 方法从运行状态转换到就绪状态后,CPU 会从就绪状态线程队列中只会选择与该线程优先级相同或优先级更高的线程去执行。在使用时直接用 Thread.yield() 静态方法就可以了。
  • setDaemon(true) 设置为后台线程。后台线程主要是为其他线程(相对可以称之为前台线程)提供服务,或“守护线程”。如JVM中的垃圾回收线程。

11 进程调度算法

  1. 先来先去服务
  2. 时间片轮转
  3. 最短进程优先
  4. 最短剩余时间优先
  5. 最高响应比优先
  6. 多级反馈队列

11.1 先来先去服务

先来先去服务调度算法是一种最简单的调度算法,也称为先进先出或严格排队方案。当每个进程就绪后,它加入就绪队列。当前正运行的进程停止执行,选择在就绪队列中存在时间最长的进程运行。
  该算法既可以用于作业调度,也可以用于进程调度。先来先去服务比较适合于常作业(进程),而不利于段作业(进程)。

11.2 时间片轮转法

轮转法是基于适中的抢占策略的,以一个周期性间隔产生时钟中断,当中断发生后,当前正在运行的进程被置于就绪队列中,然后基于先来先去服务策略选择下一个就绪作业的运行。这种技术也称为时间片,因为每个进程再被抢占之前都给定一片时间。

11.3 最短进程优先

最短进程优先是一个非抢占策略,他的原则是下一次选择预计处理时间最短的进程,因此短进程将会越过长作业,跳至队列头。该算法即可用于作业调度,也可用于进程调度。但是他对长作业不利,不能保证紧迫性作业(进程)被及时处理,作业的长短只是被估算出来的。

11.4 最短剩余时间优先

最短剩余时间是针对最短进程优先增加了抢占机制的版本。在这种情况下,进程调度总是选择预期剩余时间最短的进程。当一个进程加入到就绪队列时,他可能比当前运行的进程具有更短的剩余时间,因此只要新进程就绪,调度程序就能可能抢占当前正在运行的进程。像最短进程优先一样,调度程序正在执行选择函数是必须有关于处理时间的估计,并且存在长进程饥饿的危险。

11.5 最高响应比优先

  • 根据比率:R=(w+s)/s (R为响应比,w为等待处理的时间,s为预计的服务时间)

如果该进程被立即调用,则R值等于归一化周转时间(周转时间和服务时间的比率)。R最小值为1.0,只有第一个进入系统的进程才能达到该值。调度规则为:当前进程完成或被阻塞时,选择R值最大的就绪进程,它说明了进程的年龄。当偏向短作业时,长进程由于得不到服务,等待时间不断增加,从而增加比值,最终在竞争中赢了短进程。

11.6 多级反馈队列

  1. 设置多个就绪队列,并为各个队列赋予不同的优先级。在优先权越高的队列中,为每个进程所规定的执行时间片就越小。
  2. 当一个新进程进入内存后,首先放入第一队列的末尾,按照先来先去原则排队等候调度。如果他能在一个时间片中完成,便可撤离;如果未完成,就转入第二队列的末尾,同样等待调度…如此下去,当一个长作业(进程)从第一队列依次将到第n队列(最后队列)后,便按第n队列时间片轮转运行。
  3. 仅当第一队列空闲的时候,调度程序才调度第二队列中的进程运行;仅当第1到(i-1)队列空时,才会调度第i队列中的进程运行,并执行相应的时间片轮转。
  4. 如果处理机正在处理第i队列中某进程,又有新进程进入优先权较高的队列,则此新队列抢占正在运行的处理机,并把正在运行的进程放在第i队列的队尾。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值