线程类(Thread)简单理解

线程中的常见方法:start()、interrupt()、sleep()、run()、getPriority()

线程的启动

关于start()
1.调用start方法的顺序并不能决定线程执行的顺序

当调用start方法时,其实就是向JVM请求执行此新线程,何时能够运行并不是由start方法调用顺序决定的,而是由线程调度器决定的。
2.start方法会让两个线程同时运行

第一个主线程:创建线程执行start()方法。
第二个子线程 :就绪状态->执行状态->运行状态。
3.不能两次执行start方法(分析源码)
调用start方法时,首先会先检查此线程状态,源码中的threadStatus就表示线程状态,初始状态值是0,如果是0的话,则执行start0方法。
start0方法是native方法,由C++编写,如需查看源码,可以去openjdk里看。

Thread类中的start()和run()方法有什么区别?

start()方法中最终要的是调用了Native方法start0()用来启动新创建的线程线程启动后会自动调用run()方法.如果我们直接调用其run()方法就和我们调用其他方法一样,不会在新的线程中执行.

并发和并行的区别

并发:两个或多个事件在同一时间间隔发生。

并行:两个或者多个事件在同一时刻发生。

并行是真正意义上,同一时刻做多件事情,而并发在同一时刻只会做一件事件,只是可以将时间切碎,交替做多件事情。

网上有个例子挺形象的:

你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。

你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。

你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。

线程的状态(个人总结):

线程阻塞指的是暂停一个线程的执行以等待某个条件发生(如某资源就绪),Java 提供了大量方法来支持阻塞。

方法所属类说明备注
sleep() Thread(线程类) sleep() 允许 指定以毫秒为单位的一段时间作为参数,它使得线程在指定的时间内进入阻塞状态,不能得到CPU 时间,指定的时间一过,线程重新进入可执行状态。 典型地,sleep() 被用在等待某个资源就绪的情形:测试发现条件不满足后,让线程阻塞一段时间后重新测试,直到条件满足为止。调用sleep()方法时,线程不会释放对象,sleep()睡眠后不出让系统资源,sleep(milliseconds)需要指定一个睡眠时间,时间一到会自动唤醒。阻塞时都不会释放占用的锁(如果占用了的话)
suspend() 和 resume()两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的resume() 被调用,才能使得线程重新进入可执行状态。典型地,suspend() 和 resume() 被用在等待另一个线程产生的结果的情形:测试发现结果还没有产生后,让线程阻塞,另一个线程产生了结果后,调用 resume() 使其恢复。
yield()yield() 使当前线程放弃当前已经分得的CPU 时间,但不使当前线程阻塞,即线程仍处于可执行状态,随时可能再次分得 CPU 时间。调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程。yield()执行后线程直接进入就绪状态,马上释放cpu的执行权,但是依然保留了cpu的执行资格,所以有可能cpu下次进行线程调度还会让这个线程获取到cpu资源继续执行。
wait() 和 notify()、notifyAll()Object类所有对象都拥有这一对方法且都可以拥有锁。两个方法配套使用,调用任意对象的wait()方法使线程进入阻塞状态,并且线程中该对象上的锁被释放,让其他线程可以占用CPU,需要配合notify()或者notifyAll()使用,调用 notify() 方法导致解除阻塞的线程是从因调用该对象的 wait() 方法而阻塞的线程中随机选取的(但要等到获得锁后才真正可执行),我们无法预料哪一个线程将会被选择,所以编程时要特别小心,避免因这种不确定性而产生问题。(两种形式:1.指定以毫秒为单位的一段时间作为参数,当对应的notify() 被调用或者超出指定时间时线程重新进入可执行状态;2. 没有参数,必须对应的 notify() 被调用。)而调用notifyAll() 方法将把因调用该对象的 wait() 方法而阻塞的所有线程一次性全部解除阻塞。当然,只有获得锁的那一个线程才能进入可执行状态。

它们的功能最强大,使用也最灵活,但是这也导致了它们的效率较低,较容易出错。。。

将它们和操作系统进程间通信机制作一个比较就会发现它们的相似性:synchronized方法或块提供了类似于操作系统原语的功能,它们的执行不会受到多线程机制的干扰,而这一对方法则相当于 block 和wakeup 原语(这一对方法均声明为 synchronized)。它们的结合使得我们可以实现操作系统上一系列精妙的进程间通信的算法(如信号量算法),并用于解决各种复杂的线程间通信问题。

join()执行后线程进入阻塞状态,例如在线程B中调用了A的join(),那么线程B会进入阻塞状态,直到线程A结束或者中断线程。

yield方法使比自己低优先级的线程运行?

在java中,高优先级的可运行的线程会抢占低优先级线程的资源?

死锁

谈到阻塞,就不能不谈一谈死锁,略一分析就能发现,suspend() 方法和不指定超时期限的 wait() 方法的调用都可能产生死锁。遗憾的是,Java 并不在语言级别上支持死锁的避免,我们在编程中必须小心地避免死锁。

产生死锁的条件

1.互斥条件:一个资源每次只能被一个进程使用。
2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3.不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

wait()方法和notify()/notifyAll()方法在放弃对象监视器时的区别在于:wait()方法立即释放对象监视器,notify()/notifyAll()方法则会等待线程剩余代码执行完毕才会放弃对象监视器。

为什么wait,nofity和nofityAll这些方法不放在Thread类当中且要在synchronized同步块中被调用

java提供的锁是对象级的而不是线程级的,每个对象都有锁,通过线程获得。如果线程需要等待某些锁那么调用对象中的wait()方法就有意义了。如果wait()方法定义在Thread类中,线程正在等待的是哪个锁就不明显了。简单的说,由于wait,notify和notifyAll都是锁级别的操作,所以把他们定义在Object类中因为锁属于对象。在同步块中被调用这是JDK强制的,wait()方法和notify()/notifyAll()方法在调用前都必须先获得对象的锁。只有在synchronized 方法或块中当前线程才占有锁,才有锁可以释放。同样的道理,调用这一对方法的对象上的锁必须为当前线程所拥有,这样才有锁可以释放。因此,这一对方法调用必须放置在这样的 synchronized 方法或块中,该方法或块的上锁对象就是调用这一对方法的对象。若不满足这一条件,则程序虽然仍能编译,但在运行时会IllegalMonitorStateException 异常。

怎么唤醒一个阻塞的线程

如果线程是因为调用了wait()、sleep()或者join()方法而导致的阻塞,可以中断线程,并且通过抛出InterruptedException来唤醒它;如果线程遇到了IO阻塞,无能为力,因为IO是操作系统实现的,Java代码并没有办法直接接触到操作系统。

多线程的上下文切换

指CPU控制权由一个已经正在运行的线程切换到另外一个就绪并等待获取CPU执行权的线程的过程。

synchronized和ReentrantLock的区别

synchronized是和if、else、for、while一样的关键字,ReentrantLock是类,这是二者的本质区别。既然ReentrantLock是类,那么它就提供了比synchronized更多更灵活的特性,可以被继承、可以有方法、可以有各种各样的类变量,ReentrantLock比synchronized的扩展性体现在几点上:
(1)ReentrantLock可以对获取锁的等待时间进行设置,这样就避免了死锁
(2)ReentrantLock可以获取各种锁的信息
(3)ReentrantLock可以灵活地实现多路通知
另外,二者的锁机制其实也是不一样的:ReentrantLock底层调用的是Unsafe的park方法加锁,synchronized操作的应该是对象头中mark word

ThreadLocal用于创建线程的本地变量,该变量是线程之间不共享的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肆〇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值