JAVA SE(第n天)( 多线程)

本文详细探讨了多线程的基础知识,包括CPU调度算法、效率提升与线程池,以及线程安全、synchronized、wait/notify、线程状态和优先级。重点讲解了如何通过synchronized和Lock实现线程同步,以及wait/notify在协作中的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天学的赶紧记录,之前没赶的进度之后搞。。


目录

多线程

1.cpu基础知识

1.1为什么在进程中还需要线程呢?

 1.2CPU调度算法原理

2.多线程效率问题与底层原理

3.多线程创建方式

4.线程安全性问题

5.synchronized基本用法

6.如何保证线程同步问题

7.wait、notify注意事项

8.多线程的七种执行状态以及用户线程和守护线程

8.1多线程的七种执行状态

8.2用户线程和守护线程

9.停止线程和多线程优先级

9.1停止线程

9.2多线程优先级

10.join/wait与sleep之间的区别


多线程

1.cpu基础知识

cpu:中央处理器→1.运算器   作用运算
               2.控制器   负责发出cpu每条指令所需信息
               3.寄存器   保存运算或指令的一些临时文件


进程:1.cpu从硬盘中读取一段程序到内存中,该执行程序的实例叫进程。
     2.一个程序如果被cpu多次读取到内存中,则变成多个独立进程。

线程:线程是程序执行的最小单位,在进程中可以有多个不同的线程同时执行。(同一个过程中,更好并行处理)

线程运行在cpu之上


总结:进程是资源分配最小单位,线程是程序执行最小单位。
     


Cpu密集型/IO密集型

Cpu密集型:长时间占用cpu;例如: 视频剪辑
IO密集型 :cpu计算时间短  访问外接设备时间长
Input/output

1.1为什么在进程中还需要线程呢?

同一个应用程序中(进程),更好并行处理。

 1.2CPU调度算法原理

1.	先来先服务  缺点如果最先来执行的线程 是CPU密集型 这样话可能会一直
无法继续执行其他的线程。
2.	最短作业法  谁的计算时间短,谁先来执行。
3.	优先级调度算法  根据重要性将进程分成4个优先级
    
    优先级4  进程D负责画面----
    优先级3  进程B和进程C接受用户的指令 重要
    优先级2  后台处理器 次要
    优先级1   

2.多线程效率问题与底层原理

1.为什么使用多线程?
    采用多线程形式执行代码,目的就是为了提高程序效率。


2.串行/并行区别?
    串行 单线程执行,代码效率低代码从上到下。
    并行 多线程并行一起执行,效率高。


3.使用多线程一定效率高?
    不一定,cpu调度的算法,先把前一个任务的cpu上下文(也就是cpu寄存器和程序计数器:从汇编语言底层 
  角度,不是java源代码角度,Java源代码一句可能汇编会有四句)保存起来,然后加载新任务的上下文到这些 
  寄存器和程序计数器,最后在跳转到程序计数器所指的新位置,运行新任务。


4.什么是上下文?
    所谓多线程,在线程数远大于cpu内核数是,所有线程被cpu调度时间片所调度,在短时间内多次在运行状        
  态和就绪状态之间切换。(如果生产环境中开启几百个或几千个线程,而我们服务器内核数一般8、16、32 , 
  这么多线程都会在cpu上做上下文切换,导致效率低下)

5.一般会设置线程池:8内核的cpu可以限定最多八个线程,减少cpu做上下文切换。


6.多线程同步/异步的区别?
    同步:代码从上到下运行
    异步:单独分支运行,相互之间没有影响

3.多线程创建方式

①继承Thread
    
    new Thread(thread01).start();

②实现Runnable类
    
     Thread abc = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("abc");
            }
        });
        abc.start();

③使用匿名内部类
    
     new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("abc");
            }
        }).start();

④使用lamda表达式
     new Thread(() -> System.out.println("abc")).start();

⑤使用callable和Future创建
     
     //先创建一个ThreadCallable类
     ThreadCallable threadCallable = new ThreadCallable();
     FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(threadCallable);
     Thread thread = new Thread(integerFutureTask);
     thread.start();

⑥使用线程池例如Executor
    
    ExecutorService executorService = Executor.newCachedThreadpod();
    executorService.execute(() -> System.out.println("") );

⑦spring @Async
    

4.线程安全性问题

1.线程安全问题定义
    当多个线程共享一个全局变量(放在堆内存中),在做写操作时,可能会受到其他线程干扰,发生线程安全性    
  问题。

2.如何解决线程安全性问题?/如何实现线程同步?
    在同一JVM中,多个线程需要竞争锁资源,最终只有一个线程能够获取锁,多个线程同时抢同一把锁,谁能获    
    取到锁,谁就可以被执行,如果一直没有获取锁成功,中间就要经历锁的升级,如果一直没有获得到锁,该线    
    程就一直会阻塞等待。(核心思想:同JVM中当多个线程共享同一个全局变量时,将可能会发生线程安全性的
    代码上锁,保证只有拿到锁的线程才可以执行,没有拿到锁的线程不可以执行,需要阻止。)

3.JUC并发编程:重入锁、悲观锁、乐观锁、公平锁、非公平锁(synchronized锁)

4.代码加锁的缺点:可能会影响到程序的执行效率。

5.synchronized基本用法

1.修饰代码块
    
    synchronized(对象锁){
        需要保证线程安全的代码。
    }

2.修饰实例方法(this锁)
3.修饰静态方法(类名.class锁)

tips:1.多线程情况下,需要的是同一个对象锁。
     2.注意synchronized锁的死锁问题,锁嵌套会引发死锁问题。


6.如何保证线程同步问题

如何保证线程同步问题(如何保证线程安全性问题)?(具体操作)
    1.使用synchronized锁,jdk1.6锁的升级过程(偏量锁→轻量级锁→重量级锁)
    2.使用Lock锁,需要自己完成锁的升级过程,底层基于AQS+CAS实现。
    3.使用ThreadLocal,需要注意内存泄漏问题
    4.原子类CAS 非阻塞式

7.wait、notify注意事项

this.wait();    释放锁资源,同时当前线程会阻塞。
this.notify();  竞争锁资源,竞争到锁的线程继续运行。(只是让线程重新拥有竞争锁资源的资格,并不是直接拥有锁)

以上两个方法需要结合synchronized 锁,需要放在synchronized锁同步代码块中。


 
join():

    1.join() 底层用wait() and notify()封装的。
    2.t.join()方法只会使调用t.join()的线程进入等待池并等待t执行完毕后才会被自动唤醒(唤醒的过程封装                
    在Java虚拟机里,并不在join源代码里),并不影响同一时刻处在运行状态的其他线程。
    
  

8.多线程的七种执行状态以及用户线程和守护线程

8.1多线程的七种执行状态

多线程的七种执行状态
    初始化状态
    就绪状态
    运行状态
    死亡状态
    阻塞状态
    超时等待
    等待状态

Thread.sleep() 防止死循环导致cpu占用过高

8.2用户线程和守护线程

用户线程和守护线程
    1.java中线程分为两种:①用户线程Thread.setDaemon(false),默认用户线程
                         ②守护线程Thread.setDaemon(true)

    2.①守护线程是依赖于用户现场,用户线程退出了,守护线程也就会退出,典型的守护线程例如垃圾回收线程。
      ②用户现场是独立存在的,不会因为其他线程退出而退出。
    

9.停止线程和多线程优先级

9.1停止线程

1.如何安全的停止一个线程
    interrupt  中断 阻塞或者正在运行的线程

2.多线程yield
    主动释放cpu
    1.多线程yield会让线程从运行状态进入到就绪状态,然后调度执行其他线程。
    2.具体实现依赖于底层操作系统的任务调度器

9.2多线程优先级

多线程优先级
    1.在java语言中,每个线程都有优先级,当线程调度器有机会选择新的线程时,现场的优先级越高,越有可    
    能被选中执行,线程的优先级可以设置为1-10。
    
    tips:Orcle 为Linux 提供的java虚拟机,线程的优先级1将被忽略,即所有线程具有相同的优先级(不要    
    过度依赖优先级)
    
    2.线程的优先级用数字来表示,MIN_PRIORITY 到 MAX_PRIORITY  就是1-10,默认的NORM_PRIORITY = 5

    3.如果cpu很繁忙,优先级越高的线程能获得更多的时间片,但是cpu空闲时,设置的优先级几乎没什么用。

10.join/wait与sleep之间的区别

sleep(long)   睡眠期间不释放锁 
join(long)    先执行调用join方法的线程,等待中释放锁,底层基于wait()封装
wait(long)    在等待中释放锁,需在synchronized锁中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cxy好好先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值