一、进程和线程的关系
1.1进程process
进程是程序一次动态执行的过程,是程序运行的基本单位。
1.2线程 thread
线程又叫做轻量级进程,是CPU调度的最小单位。 线程从属于进程,是程序的实际执行者。一个进程至少包含一个主线程,也可以有更多的子线程。
二、线程的创建和使用
2.1 java中的线程类
java中用Thread类表示线程,所有的线程对象都必须是Thread 类或其⼦类的实例。
2.1.1使用Runnable类使用线程
Thread类的构造函数
根据Thread的构造函数,我们可以先创建一个类继承于 Runnable 类
Runnable类
java中Runnable类存在一个虚拟方法需要实现,我们通过实现这个方法,并创建对象,再传入Thread生成的对象中,来构造线程,最后用start()来运行线程
创建TestRunnable类继承于Runnable,再实现run方法
创建一个TestRunnable类的对象t,再将t传入新创建的线程对象thread中
2.1.2使用lambda表达式使用线程
2.2多线程
2.2.1并行与并发
并发: 处理器在不同时间处理任务,多个任务不会在同一时间执行
并行: 把任务分给多个处理器,多个任务一定会在同时执行
所以单核处理器的计算机无法并行地执行任务。任务并发时,单核计算机会分时进行任务的执行,因为分时执行的时间很短,所以看上去就像是同时执行一样。
2.2.2多个线程同时运行
创建4个线程,使他们分别打印10次1,2,3,4这几个数字,并开启这4个线程
得到的多个结果各不相同,且从多个结果中无法找到运行顺序的规律。
这是因为,当运行这4个线程时,他们将同时被执行,但根据操作系统调度,任意线程准备就绪时就会被操作系统执行,它们就绪的瞬间不同,且操作系统有自己的调度方式,所以会得到不同的结果。
2.2.3线程安全问题
当我们用多个线程对通一个区域进行改变时,就会出现共享区域的问题。因为线程中任意一段代码被调度的顺序都是不确定的,也就是任意一行代码都有可能被立刻执行,而当线程运行需要一定顺序时,它的无序性就会导致我们可能无法得到正确的数据。
例如我们对同一数据进行加和减的操作,多线程运行就有可能出现多个线程获取的数据不同同步,从而出现问题。这也就是线程安全的问题
线程安全:一个类可以在多个线程中直接使用
线程不安全:不可以在多个线程中使用,多个线程同时写入操作时,会对共享区域产生坏的影响。
2.2.4用关键字synchronized解决线程安全问题
java中存在synchronized关键字,表示这块区域只允许被一个线程使用,相当于加锁,给共享的区域加上锁,只有一个线程可以拿到代码块,而其他的线程只能等待。
一般只在对共享区域进行写的操作时才使用同步操作,这样可以使得线程的高效性最大化,如果同步的区域过大,会导致多线程操作趋向于单线程操作,从而失去了多线程速度快的优势。
2.2.5线程之间的通信
例如出现4个线程,前1,2,3线程的都执行完后某个方法后,才可以执行4线程中的代码,不然会导致数据错误的情况,我们将需要控制线程4代码的执行顺序。
可以采用Blocked阻塞锁来进行线程之间的通信,阻塞锁的作用相当于在线程之间建立了一个通道,a线程向通道中传输自己的信息,b线程从通道中拿取信息,当b线程可以从通道中拿到信息时再继续运行,而通道中阻塞时,a线程将等待通道中出现空位,向里面传递信息后再向下执行。
A,B两个线程同时执行,到达阻塞锁时各自进行判断
A线程,到达阻塞锁时,获取通道的状态,当通道无空间,进行等待。当通道有空位,传入信息,继续向下执行。
B线程,到达阻塞锁时,获取通道的状态,当通道无信息,进行等待。当通道有信息,得到信息,继续向下执行。
通过阻塞锁的方式,可以一定程度上控制线程的执行顺序,达到想要的效果。