JUC(一)——JUC简介

x33g5p2x  于2021-09-24 转载在 其他  
字(2.9k)|赞(0)|评价(0)|浏览(266)

1、什么是JUC?

java.util.concurrent 在并发编程中使用的工具类。

2、进程与线程

进程: 后台运行的每一个程序就是一个进程,是一个正在执行的程序。比如用QQ音乐放音乐,同时用QQ聊天,每一个都是一个进程。

线程: 线程是进程中的一个独立的控制单元,一个进程中至少包含一个线程。比如,我们使用Idea写代码的同时,idea可以进行一些语法检查,这就是idea的一些线程。

更为形象的例子:

一个正在运行的软件(如迅雷)就是一个进程,一个进程可以同时运行多个任务( 迅雷软件可以同时下载多个文件,每个下载任务就是一个线程), 可以简单的认为进程是线程的集合。
1、Java程序在执行的时候默认是有两个线程的,一个是负责java程序执行的main线程,也叫主线程,另一个是负责垃圾回收机制的GC线程。
2、Java是开不了线程的,因为Java是运行在虚拟机之上的,无法直接操作硬件。通过本地方法(private native void start0())去调底层的C++。

3、并行与并发

并发:同一时刻多个线程操作同一资源。比如春运抢票,电商秒杀等。
对于单核CPU来说,某一时刻只能有一个线程运在行,多个线程间快速切换,形成一种并发的效果。线程是谁抢到谁执行,执行多长时间也是由CPU说了算。

并行: 多项工作同时执行。

只有在CPU多核的情况下,多个线程才可以同时执行。

public class Test {
    public static void main(String[] args) {
        // 获取cpu的核数
        // CPU 密集型,IO密集型
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
}

总结:

并发:单核CPU,模拟出多条线程,CPU快速轮流执行。
并行:多核CPU,开启多条线程,CPU同时执行。

四、并发编程的本质

多线程的好处:可以充分利用CPU的资源
1、可以同时并发执行多个任务。
2、最大限度的降低CPU的闲置时间,从而提高CPU的利用率。

1、实际生活案例

比如饭店做饭的例子,厨师炒菜需要半小时,煮面需要半小时,如果饭店只有一个厨师,炒好菜后然后煮面,那么做好饭的时间就是一个小时,客人会等不急,这样肯定是不行的。如果饭店有2个厨师,一个厨师负责炒菜,另一个厨师负责煮面,只需要半个小时就可以做好饭。如果把每个厨师看做一个线程,多个厨师即多线程,就可以提高工作的效率。

2、多线程应用场景

  • 一般线程之间比较独立,互不影响
  • 一个线程发生问题,一般不影响其它线程

3、编程体验多线程

3.1 顺序编程

顺序编程:程序从上往下的同步执行,即如果第一行代码执行没有结束,第二行代码就只能等待第一行执行结束后才能结束。

public class OrderProgramma {
    public static void main(String[] args) throws Exception {
        // 顺序编程:先炒菜再煮面
        cooking();
        noodles();

    }
    private static void cooking() throws Exception {
        System.out.println("开始炒菜...\t" + new Date());
        Thread.sleep(5000);
        System.out.println("结束炒菜...\t" + new Date());
    }

    private static void noodles() throws Exception {
        System.out.println("开始煮面...\t" + new Date());
        Thread.sleep(5000);
        System.out.println("结束煮面...\t" + new Date());
    }
}

可以看出,顺序编程,先炒菜后煮面,总共耗时10秒。

3.2 并发编程

并发编程:多个任务可以同时做,任务与任务之间比较独立,互不影响。

public class ThreadProgramma {
    public static void main(String[] args) {
        // 多线程编程:一边炒菜一边煮面
        new Cooking().start();
        new Noodles().start();
    }

    static class Cooking extends Thread {
        @Override
        public void run() {
            System.out.println("开始炒菜...\t" + new Date());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("结束炒菜...\t" + new Date());
        }
    }

    static class Noodles extends Thread {
        @Override
        public void run() {
            System.out.println("开始煮面...\t" + new Date());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("结束煮面...\t" + new Date());
        }
    }
}

可以看到,并发编程,一边炒菜一边煮面总共用时5秒,比顺序编程更快,因为并发编程可以同时运行,而不必等前面的代码运行完之后才允许后面的代码。

4、线程上下文切换:

同一个时刻一个CPU只能做一件事情,即同一时刻只能一个线程中的部分代码,假如有两个线程,Thread-0和Thread-1,刚开始CPU说Thread-0你先执行,给你3毫秒时间,Thread-0执行了3毫秒时间,但是没有执行完,此时CPU会暂停Thread-0执行并记录Thread-0执行到哪行代码了,当时的变量的值是多少,然后CPU说Thread-1你可以执行了,给你2毫秒的时间,Thread-1执行了2毫秒也没执行完,此时CPU会暂停Thread-1执行并记录Thread-1执行到哪行代码了,当时的变量的值是多少,此时CPU又说Thread-0又该你,这次我给你5毫秒时间,去执行吧,此时CPU就找出上次Thread-0线程执行到哪行代码了,当时的变量值是多少,然后接着上次继续执行,结果用了2毫秒就Thread-0就执行完了,就终止了,然后CPU说Thread-1又轮到你,这次给你4毫秒,同样CPU也会先找出上次Thread-1线程执行到哪行代码了,当时的变量值是多少,然后接着上次继续开始执行,结果Thread-1在4毫秒内也执行结束了,Thread-1也结束了终止了。CPU在来回改变线程的执行机会称之为线程上下文切换。

5、多线程不利的方面:

1、线程需要占用内存,线程越多占用的内存也就越多。
2、高并发问题

相关文章