进程、线程
-
进程:进程是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。可以理解为一个java应用。
-
线程:线程是进程的一个执行路径,一个进程中至少有一个线程,进程中的多个线程共享进程的资源。
一个进程中有多个线程,多个线程共用进程的堆和方法区资源,但是每个线程有自己的程序计数器和栈。
多线程和锁的关系
只有拿到锁的线程才能访问共享资源,多线程之间的通信和协作,通常使用锁和等待/通知机制来实现。
并发、并行
简单说,轮流做是并发,一起做是并行。
线程创建方式
-
继承Thread类,重写run()方法,调用start()方法启动线程
一个例子
这段代码输出结果可能是ab或者ba。
-
实现 Runnable 接口,重写run()方法
上面两种都是没有返回值的。
-
实现Callable接口,重写call()方法,这种方式可以通过FutureTask获取任务执行的返回值
JVM执行start方法,会先创建一条线程,由创建出来的新线程去执行thread的run方法,这才起到多线程的效果。直接执行run方法就相当于执行一个普通的方法。直接执行thread中的run方法也是相当于顺序执行run方法。
线程等待、休眠与通知
等待
休眠
等待和休眠区别
通知
实例
执行顺序
线程上下文切换
使用多线程的目的是为了充分利用CPU,但是我们知道,并发其实是一个CPU来应付多个线程。
为了让用户感觉多个线程是在同时执行的, CPU 资源的分配采用了时间片轮转也就是给每个线程分配一个时间片,线程在时间片内占用 CPU 执行任务。当线程使用完时间片后,就会处于就绪状态并让出 CPU 让其他线程占用,这就是上下文切换。
线程间有哪些通信方式
volatile
的作用主要
-
保证可见性: 当一个变量被声明为
volatile
后,对该变量的写操作会立即被其他线程所看到,保证了多个线程之间对该变量的可见性。换句话说,一个线程对volatile
变量的修改对其他线程是可见的,不会出现线程间的数据不一致问题。 -
禁止指令重排序:
volatile
变量的读写操作会插入内存屏障,防止编译器和处理器对其进行指令重排序优化,保证了代码执行的顺序性。这样可以确保对volatile
变量的写操作先于后续的读操作,避免出现因指令重排序导致的意外结果。
总的来说,volatile
主要用于在多线程环境中确保变量的可见性和一致性,它适用于一种场景:变量被多个线程共享,并且这些线程可能会同时读写这个变量。通过使用 volatile
关键字,可以有效地避免由于线程间数据不一致导致的并发问题。