线=程=的=基=本=概=念

进程/线程/携程/纤程

进程:就是一个在内存中正在运行的程序。
线程:就是进程中的一条执行路径。

创建线程的几种方式:

  • 继承Thread,重写run()
  • 实现 Runnable 接口(也可以 Lambda 表达式)
  • Exector+Runnable/Callable

操作系统运行线程的策略:

  • 按照线程优先级
  • 按照时间片

线程的常用方法以及状态转换

在这里插入图片描述

Thread.sleep()

让线程进入等待状态,但是如果是有sync同步锁的情况下,不会交出锁。再睡眠时间到了之后,会自动进入就绪状态。如果sleep()了过长时间,可以通过interrupt()叫醒,并在sleep的run线程中中catch那个异样来叫醒。sleep()方法本身是native方法。

Thread.yield()

让线程交出CPU使用权,回到就绪状态。但是下一刻依然可能被CPU执行,并不表示一定会让其他线程得到CPU。所以**Thread.yield()**的本质是让出一下CPU。

t.join()

合并两个线程,如果在t1线程里调用t2.join(),t1就会进入等待,要一直等待t2执行完才会继续执行。t.join() 经常拿来等待另外一个线程的结束。

o.wait()

这个o代表锁对象。让线程进入等待状态,有sync同步锁的情况下,会出锁,与sleep不同。o.wait()可以传入时间也可以不传入,如果不传入,则需要另一个线程通过 o.notify() / o.notifyAll() 方法唤醒。如果传入里时间,到时候会自然醒,当然也可以通过 o.notify() / o.notifyAll() 方法唤醒。o.notify() 会随机唤醒一个线程,o.notifyAll() 会唤醒所有线程。o.wait()方法需要在synchronized块中执行(sleep和park可以任意地执行);

LockSupport.park()

让线程进入等待状态。有sync同步锁的情况下,不会出锁,与sleep相同。需要另一个线程通过 LockSupport.unpark() 来唤醒。可以任意地执行。

t.interrupt()

当你在sleep()、wait()、join()、park() 的时候都可以通过 interrrupt() 来打断。通过在run方法里catch 来自 interrrupt 的异常来做处理。

题:如何保证多个线程顺序执行

在主线程里,一次调用每个线程的 join() 方法。

Synchronized关键字

乐观锁与悲观锁

1、悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。悲观锁的实现,往往依靠底层提供的锁机制;悲观锁会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁。悲观锁的实现比如synchronized关键字。

2、乐观锁:假设不会发生并发冲突,每次不加锁而是假设没有冲突而去完成某项操作,只在提交操作时检查是否违反数据完整性。如果因为冲突失败就重试,直到成功为止。乐观锁的实现可以添加版本号,或者CAS。

乐观锁的缺点是不能解决部分脏读的问题,例如ABA问题(下面会讲到)。

在实际生产环境里边,如果并发量不大且不允许脏读,可以使用悲观锁解决并发问题;但如果系统的并发非常大的话,悲观锁定会带来非常大的性能问题,所以我们就要选择乐观锁定的方法。

发布了40 篇原创文章 · 获赞 0 · 访问量 397

猜你喜欢

转载自blog.csdn.net/weixin_43780400/article/details/105570147