Java并发基础概念

进程与线程

进程

  • 程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至 CPU,数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理 IO 的
  • 进程是系统分配资源的最小单元

线程

  • 一个进程可以有多个线程
  • 线程是cpu调度的基本单位,线程之间共享进程资源

进程与线程的区别

  • 进程的独立的,而线程存在于进程内,是进程的一个子集
  • 进程拥有共享的资源,供内部的线程共享

并行与并发

并发

单核 cpu 下,线程实际还是 串行执行 的。操作系统中有一个组件叫做任务调度器,将 cpu 的时间片(windows下时间片最小约为 15 毫秒)分给不同的程序使用,只是由于 cpu 在线程间(时间片很短的)切换非常快,人类感觉是同时运行的 。总结为一句话就是: 微观串行,宏观并行
一般将这种现场轮流使用CPU的做法叫做并发,concurrent
在这里插入图片描述

并行

在这里插入图片描述

简单来说,并发就是一段时间内,我干完这个,再去干那个,相当于一段时间内一个人干多件事情。而并行就是在某一个时间,我同时干了多件事,比如说我一边洗脚一边打王者荣耀。在现在的多CPU处理器下,并发和并行一般是同时存在的

同步和异步

  • 需要等待结果返回,才能继续运行就是同步
  • 不需要等待结果返回,就能继续运行就是异步

同步就相当于是 当客户端发送请求给服务端,在等待服务端响应的请求时,客户端不做其他的事情。当服务端做完了才返回到客户端。这样的话客户端需要一直等待。用户使用起来会有不友好。
异步就是,当客户端发送给服务端请求时,在等待服务端响应的时候,客户端可以做其他的事情,这样节约了时间,提高了效率。
存在就有其道理 异步虽然好 但是有些问题是要用同步用来解决,比如有些东西我们需要的是拿到返回的数据再进行操作的。这些是异步所无法解决的。

Java创建线程

继承Thread类

        //继承Thread类,重写run方法
        new Thread("A"){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        }.start();

实现Runnable接口

        //实现runnable接口
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        },"B").start();

        //lamba表达式简化
        new Thread(()->{
            System.out.println(Thread.currentThread().getName());
        },"C").start();

使用FuntureTash类配合Thread

        //使用FutureTash类
        FutureTask<Integer> task=new FutureTask<>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return 100;
            }
        });
        new Thread(task,"D").start();
        System.out.println(task.get());

使用线程池,后面会专门讲解

线程上下文切换

因为以下一些原因导致CPU不再执行当前线程,转而执行其他线程

  • 线程的CPU时间片用完
  • 垃圾回收,导致的STW
  • 有更高优先级的线程需要运行
  • 线程自己调用了 sleep、yield、wait、join、park、synchronized、lock 等方法

当上下文切换发生时,操作系统需要保存当前线程的状态,恢复执行线程的状态。Java中对应的概念为程序计数器,它的作用是记住下一条jvm指令的执行地址,是线程私有的。
频繁上下文切换会降低性能

Thread常见方法

在这里插入图片描述
在这里插入图片描述

start 与 run

我们尝试使用run或者start来开启线程

        new Thread("A"){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"    runing....");
            }
        }.run();

        new Thread("B"){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"    runing....");
            }
        }.start();
main    runing....
B    runing....

Process finished with exit code 0

上面发现:直接调用run只是调用类的一个普通方法,并没有开启多线程。只有调用了start方法才开启了多线程。
查看源码
在这里插入图片描述
在这里插入图片描述
这里调用run方法只是调用了Runnable接口里的方法,相当于我们只是main线程调用了一个普通方法而已。
在这里插入图片描述
而调用我们的start方法后,最后会执行start0()这个本地方法,由JVM来创建一个线程,这时该线程处于就绪状态(NEW),并没有运行。当该线程分得CPU时间段后,会调用run方法执行。此时进入了运行状态

sleep与yield

sleep

  • 调用sleep会使线程从Runnig状态进入time_waiting状态
  • 睡眠过后的线程会进入到就绪态,不一定会马上执行

yield:

  • 调用yield会使线程从Runnig状态进入Runable状态,然后尝试调用其他线程

线程优先级

设置较高的线程优先级会使调度器优先调度该线程,但只是一个提示,可能调度器并不会理会它

join

    static int r = 0;
    public static void main(String[] args) throws InterruptedException {
        test1();
    }
    private static void test1() throws InterruptedException {
        System.out.println("开始");
        Thread t1 = new Thread(() -> {
            System.out.println("开始");
            try {
                sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("结束");
            r = 10;
        });
        t1.start();
        System.out.println("结果为:"+ r);
        System.out.println("结束");
    }

因为t1和t2线程是并行执行的,而t1需要等待1s才能算出r。所以只能打印出r=0
解决方法:加sleep行不行??不行,因为有可能t1的执行时间很长,不能够准确判断什么时候执行完毕。加t1.join在t1.start()之后便可以,这样便可以等待t1运行完才执行后面的线程了

带时间参数的join,等待指定时间后,最多等待指定时间就必须执行了

interrupt方法详解

    public static void main(String[] args) throws InterruptedException {
        Thread x=new Thread(()->{
            try {
                sleep(4000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        },"A");
        x.start();
        x.interrupt();
        System.out.println(x.isInterrupted());
    }

打断 sleep,wait,join 的线程
这几个方法都会让线程进入阻塞状态
打断 sleep,wait,join 的线程, 会清空打断状态;
打断正常运行的线程, 不会清空打断状态

线程状态

操作系统层面的五种线程状态

在这里插入图片描述
在这里插入图片描述

Java的六种状态

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值