多线程原理

身处后面的main却先执行 本身就是多线程
image.png
同时开辟一个新的线程
image.png
多线程执行时,在栈内存中,其实每一个执行线程都有一片自己所属的栈内存空间。进行方法的压栈和弹栈。
image.png

Thread类

image.png
image.png

Runnable类

public static Thread currentThread() :返回对当前正在执行的线程对象的引用。
public Thread(Runnable target) :分配一个带有指定目标新的线程对象。
public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。

image.png
分配一个带有指定目标Runnable对象
image.png

多线程共享

若想要线程中的资源达到共享就可以使用runnable类
创建一个runnable的对象但是可以传给两个thread对象
若不想要线程的资源共享可以创建thread对象
创建多个thread可以使用各自的资源(在此对象中加一个static关键字可以达到资源共享)
image.png

Thread和Runnable的区别

如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
实现Runnable接口比继承Thread类所具有的优势:

  1. 适合多个相同的程序代码的线程去共享同一个资源
  2. 可以避免java中的单继承的局限性
  3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
  4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。

扩充:在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用 java命令执行一个类的时候,实际上都会启动一个JVM,每一个JVM其实在就是在操作系统中启动了一个进程。

耦合度

你和你的室友的耦合度很高 和你的小学同学很高 但是他们两者之间没什么耦合度

并发与并行

并发:指两个或多个事件在同一个时间段(几分钟几秒钟)内发生
并行:指两个或多个事件在同一时刻发生(同时发生)
image.png
在操作系统中,安装了多个程序,并发指的是在一段时间内宏观上有多个程序同时运行,这在单 CPU 系统中,每 一时刻只能有一道程序执行,即微观上这些程序是分时的交替运行,只不过是给人的感觉是同时运行,那是因为分 时交替运行的时间是非常短的。
而在多个 CPU 系统中,则这些可以并发执行的程序便可以分配到多个处理器上(CPU),实现多任务并行执行, 即利用每个处理器来处理一个可以并发执行的程序,这样多个程序便可以同时执行。目前电脑市场上说的多核 CPU,便是多核处理器,核 越多,并行处理的程序越多,能大大的提高电脑运行的效率。

线程与进程

进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多 个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创 建、运行到消亡的过程。
线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程 中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程

线程调度:

分时调度 :

所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。

抢占式调度 :

优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为 抢占式调度。
image.png
设置线程的优先级 抢占式调度详解 大部分操作系统都支持多进程并发运行,现在的操作系统几乎都支持同时运行多个程序。比如:现在我 们上课一边使用编辑器,一边使用录屏软件,同时还开着画图板,dos窗口等软件。此时,这些程序是 在同时运行,”感觉这些软件好像在同一时刻运行着“。
实际上,CPU(中央处理器)使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核而 言,某个时刻,只能执行一个线程,而 CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是 在同一时刻运行。 其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的 使用率更高

创建线程类

image.png
抢占式执行
image.png
单线程
image.png\
不需要自己去调用run 自己去调用start方法 让jvm静态调用run
image.png

线程不安全

每次售票不同步,是不安全的
线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写 操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步, 否则的话就可能影响线程安全。
image.png

线程同步机制

同步代码块(更加便捷)

同步锁

对于非static方法,同步锁就是this(成员方法)。
对于static方法,我们使用当前方法所在类的字节码对象(类名.class)(静态方法是唯一的,类唯一,而成员方法可以创建多个和对象,是不唯一的需要用synchronize加以限制才能唯一)。

  1. 锁对象 可以是任意类型。
  2. 多个线程对象 要使用同一把锁。
  3. 注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着 (BLOCKED)。

image.png

解决并行不安全的方法:使用同步锁

线程安全的代码运行效率都很低,线程不安全的代码运行效率都很(StringBuffer和StringBuilder)
线程安全的代码是串行的,线程不安全的代码是并行的
具有互斥效果,一号进入之后,其他窗口就进入不了这个循环
image.png

同步方法(更加规矩)

机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作, 同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象
四个thread对象都通过runnable对象调用run方法
image.png
image.png

lock接口

image.png
image.png

线程状态

线程报异常只会杀死自己跟其他的线程无关
image.png
image.png

Timed Waiting(计时等待)

一个正在限时等待另一个线程执行一个(唤醒)动作的线程处于这一状态
通过案例可以发现,sleep方法的使用还是很简单的。我们需要记住下面几点:
image.png

  1. 进入 TIMED_WAITING 状态的一种常见情形是调用的 sleep 方法,单独的线程也可以调用,不一定非要有协
    作关系。
  2. 为了让其他线程有机会执行,可以将Thread.sleep()的调用放线程run()之内。这样才能保证该线程执行过程
    中会睡眠
  3. sleep与锁无关,线程睡眠到期自动苏醒,并返回到Runnable(可运行)状态。
  4. sleep()中指定的时间是线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就 开始立刻执行。

image.png

BLOCKED(锁阻塞)

一个正在阻塞等待一个监视器锁(锁对象)的线程处于这一状态
image.png

Waiting(无限等待)

一个正在无限期等待另一个线程执行一个特别的(唤醒)动作的线程处于这一状态
线程进入到无限等待的状态时会失去同步锁
image.png
image.png
sleep休眠醒来没有锁就会进去到阻塞态
image.png