Java多线程

199 篇文章 0 订阅
2 篇文章 0 订阅

线程和进程的关系
线程就是轻量级进程,是程序执行的最小单位。

多进程的方式也可以实现并发,为什么我们要使用多线程?

共享资源在线程间的通信比较容易。
线程开销更小。
进程和线程的区别?

进程是一个独立的运行环境,而线程是在进程中执行的一个任务。他们两个本质的区别是是否单独占有内存地址空间及其它系统资源(比如I/O):
进程单独占有一定的内存地址空间,所以进程间存在内存隔离,数据是分开的,数据共享复杂但是同步简单,各个进程之间互不干扰;而线程共享所属进程占有的内存地址空间和资源,数据共享简单,但是同步复杂。
进程单独占有一定的内存地址空间,一个进程出现问题不会影响其他进程,不影响主程序的稳定性,可靠性高;一个线程崩溃可能影响整个程序的稳定性,可靠性较低。
进程单独占有一定的内存地址空间,进程的创建和销毁不仅需要保存寄存器和栈信息,还需要资源的分配回收以及页调度,开销较大;线程只需要保存寄存器和栈信息,开销较小。
进程是操作系统进行资源分配的基本单位,而线程是操作系统进行调度的基本单位,即CPU分配时间的单位 。

创建线程
有三种方式

继承Thread类,重写run方法
实现Runnable接口,实现run方法
通过线程池创建
通过Callable/Future创建(需要返回值的时候)

线程基本操作
sleep

当前线程睡一段时间

yield

这是一个静态方法,一旦执行,它会使当前线程让出一下CPU。但要注意,让出CPU并不表示当前线程不执行了。当前线程在让出CPU后,还会进行CPU资源的争夺,但是是否能够再次被分配到就不一定了。

join

等待另外一个线程的结束,当前线程才会运行

public class ThreadJoin {
    volatile static int i = 0; 
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            for (i = 0; i < 10000; i++) {
            }//欢迎加入Java开发交流君样:909038429
        });
        thread.start();
        // join 方法表示主线程愿意等待子线程执行完毕后才继续执行
        // 如果不使用join方法,那么i输出的可能是一个很小的值,因为还没等子线程
        // 执行完毕后,主线程就已经执行了打印i的操作
        thread.join();
        System.out.println(i);
    }
}

线程状态切换
CAS
比较与交换的意思

举个例子:

内存有个值是3,如果用Java通过多线程去访问这个数,每个线程都要把这个值+1,之前是需要加锁,即synchronized关键字来控制,但是JUC的包出现后,有了CAS操作,可以不需要加锁来处理,流程是:

第一个线程:把3拿过来,线程本地区域做计算+1,然后把4写回去,

第二个线程:也把3这个数拿过来,线程本地区域做计算+1后,在回写回去的时候,会做一次比较,如果原来的值还是3,那么说明这个值之前没有被打扰过,就可以把4写回去,如果这个值变了,假设变为了4,那么说明这个值已经被其他线程修改过了,那么第二个线程需要重新执行一次,即把最新的4拿过来继续计算,回写回去的时候,继续做比较,如果内存中的值依然是4,说明没有其他线程处理过,第二个线程就可以把5回写回去了。

流程图如下:
在这里插入图片描述

ABA问题
CAS会出现一个ABA的问题,即在一个线程回写值的时候,其他线程其实动过那个原始值,只不过其他线程操作后这个值依然是原始值。

如何来解决ABA问题呢?

我们可以通过版本号或者时间戳来控制,比如数据原始的版本是1.0,处理后,我们把这个数据的版本改成变成2.0版本, 时间戳来控制也一样,

以Java为例,AtomicStampedReference这个类,它内部不仅维护了对象值,还维护了一个时间戳。

当AtomicStampedReference对应的数值被修改时,除了更新数据本身外,还必须要更新时间戳。

当AtomicStampedReference设置对象值时,对象值以及时间戳都必须满足期望值,写入才会成功。

因此,即使对象值被反复读写,写回原值,只要时间戳发生变化,就能防止不恰当的写入。

Note:

CAS的底层实现

Unsafe.cpp-->Atom::cmpxchg--Atomic_linux_x86_inline.hpp-->调用了汇编的LOCK_IF_MP方法

Multiple_processor

lock cmpxchg

虽然cmpxchg指令不是原子的,但是加了lock指令后,则cmpxhg被上锁,不允许被打断。在多核CPU中,必须加lock

使用CAS好处

jdk早期是重量级别锁 ,通过0x80中断 进行用户态和内核态转换,所以效率比较低,有了CAS操作,大大提升了效率。

对象的内存布局
这里说到的对象内存布局和具体的虚拟机实现是有关系的,我们讨论的是Hotspot的实现。
image
最新2020整理收集的一些高频面试题(都整理成文档),有很多干货,包含mysql,netty,spring,线程,spring cloud、jvm、源码、算法等详细讲解,也有详细的学习规划图,面试题整理等,需要获取这些内容的朋友请加Q君样:909038429
/./*欢迎加入java交流Q君样:909038429一起吹水聊天

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值