qidao123.com技术社区-IT企服评测·应用市场

标题: 【JavaEE -- 多线程进阶 - 面试重点】 [打印本页]

作者: 来自云龙湖轮廓分明的月亮    时间: 2025-5-12 01:58
标题: 【JavaEE -- 多线程进阶 - 面试重点】
1. 常见锁战略

加锁过程中,处理冲突的过程中,涉及到一些差别的处理方式。
1.1 乐观锁和悲观锁


1.2 轻量级锁和重量级锁

按加锁开销的大小分:

轻量和重量是加锁之后对结果的评价,乐观和悲观是加锁之前,对未发生的事情举行的预估,整体来说,这两种角度描述的是同一个事情
1.3 自旋锁和挂起等待锁


synchronized具有自顺应能力


1.4 普通互斥锁和读写锁

一个线程对于数据的访问,主要存在两种操作:读数据和写数据。

一个线程加 读锁的时间,另一个线程只能读,不能写。一个线程加 写锁的时间,另一个线程,不能读也不能写
1.5 公平锁和非公平锁

假如三个线程A,B,C,A先尝试获取锁,获取乐成,然后B再尝试获取锁,获取失败,阻塞等待;然后C也尝试获取锁,C也获取失败,阻塞等待。

1.6 可重入锁和不可重入锁


2. Synchronized原理(特点、加锁过程、自顺应)

2.1 Synchronized基本特点

2.2 Synchronized加锁过程

当线程执行到Synchronized的时间,假如这个对象当前处于为加锁的状态,就会履历以下过程:
2.3 锁消除

锁消除也是synchronized中内置的优化战略。编译器优化的一种方式,编译器编译代码的时间,假如发现这个代码,不必要加锁,就会自动把锁给干掉。针对一眼看上去就不涉及安全题目的代码,可以或许把锁消除掉,对于其他的很多含糊其词的,都不会消除。
2.4 锁粗化

锁粗化,会把多个细粒度的锁,合并成一个粗粒度的锁。粒度指的是synchronized {}里大括号里面包含代码越少,就认为锁的粒度越细,包含的代码越多,就认为锁的粒度越粗。
通常情况下,是更偏于让锁的粒度细一些,更有利于多个线程并发执行的,但偶然间也希望粒度粗点好.
如A给B交接使命,打电话,交接使命1,挂电话。打电话,交接使命2,挂电话。打电话,交接使命3,挂电话。粗化成,打电话,交接使命1,2,3.挂电话。把这三个合并一个粗粒度的锁,粗化进步了效率
小结:synchronized的优化操作

3. CAS(compare and swap)

CAS是一个特殊的cpu的指令,完成的工作就是 比较 和 互换。是单个cpu指令,本身是原子的,同时完成 读取内存,比较是否相称,修改内存
CAS的伪代码:
比较address内存地址中的值,是否和expected寄存器中的值雷同,假如雷同,就把swap寄存器的值和address内存的值,举行互换,返回true。假如不雷同,直接返回false。

  1. public class ThreadDemo34  {
  2.     // AtomicInteger: Java标准库中,对cas又进一步的封装,提供了一些工具类,即原子类
  3.     // 使用原生的int 会出现线程安全问题 ,不使用加锁,使用AtomicInteger替换int也能保证线程安全
  4.     // private static int count = 0;
  5.     private static AtomicInteger count = new AtomicInteger(0);
  6.     public static void main(String[] args) throws InterruptedException {
  7.         Thread t1 = new Thread(() -> {
  8.             for (int i = 0; i < 50000; i++) {
  9.                 //getAndIncrement 对变量的修改,是一个cas指令,即这个指令天然就是原子的
  10.                 //count++;
  11.                 count.getAndIncrement();
  12.                 // ++count;
  13.                 //count.incrementAndGet();
  14.                 // count += n;
  15.                 //count.getAndAdd(n);
  16.             }
  17.         });
  18.         Thread t2 = new Thread(() -> {
  19.             for (int i = 0; i < 50000; i++) {
  20.                 //count++;
  21.                 count.getAndIncrement();
  22.             }
  23.         });
  24.         t1.start();
  25.         t2.start();
  26.         t1.join();
  27.         t2.join();
  28.         System.out.println(count);
  29.     }
  30. }
复制代码
3.1 CAS 的ABA题目怎么办理

假如去ATM取钱,里面有1000,要取500,取钱的时间ATM卡了,按了一下没反应(t1线程),又按了一下(t2线程),此时此时产生了两个线程,去尝试扣款操作,此处 假如按CAS的方式扣款,这样是没题目的。当又来个t3线程给账户存了500,此时t1线程就不知道当前的1000是始终没变还是变了又变返来了。
办理方案
4. Callable接口


  1. public class ThreadDemo35 {
  2.     private static  int sum = 0;
  3.     public static void main(String[] args) throws InterruptedException {
  4.         // 创建一个新线程,用新的线程实现从1+到1000
  5.         // 不用callable
  6.         Thread t = new Thread(new Runnable() {
  7.             @Override
  8.             public void run() {
  9.                 int result = 0;
  10.                 for (int i = 0; i <= 1000; i++) {
  11.                     result += i;
  12.                 }
  13.                 sum = result;
  14.             }
  15.         });
  16.         t.start();
  17.         t.join();
  18.         // 主线程获取到计算结果
  19.         // 此处想要获取到结果,就需要弄一个成员变量保持上述结果
  20.         System.out.println("sum= " + sum);
  21.     }
  22. }
复制代码

  1. import java.util.concurrent.*;
  2. // Callable 接口
  3. public class ThreadDemo36 {
  4.     public static void main(String[] args) throws ExecutionException, InterruptedException {
  5.         // 期望线程的入口方法里,返回值是啥类型,此处的泛型就是什么类型 这里希望返回值是Integer
  6.         Callable<Integer> callable = new Callable<Integer>() {
  7.             @Override
  8.             public Integer call() throws Exception {
  9.                 int result = 0;
  10.                 for (int i = 0; i <= 1000; i++) {
  11.                     result += i;
  12.                 }
  13.                 return result;
  14.             }
  15.         };
  16.         //Thread没有提供构造函数传入callable
  17.         // 引入一个FutureTask类,作为Thread和callable的粘合剂 未来的任务,相当于一个凭据
  18.         FutureTask<Integer> futureTask = new FutureTask<>(callable);
  19.                
  20.         Thread t = new Thread(futureTask);
  21.         t.start();
  22.         // 接下来这个代码不需要join,使用futureTask获取到结果
  23.         // futureTask.get() 这个操作也具有阻塞功能,如果线程还没有执行完毕,get就会阻塞,等到线程执行完了,
  24.             //return的结果就会被get返回回来
  25.         System.out.println(futureTask.get());
  26.     }
  27. }
复制代码
5. JUC(java.util.concurrent)的常见类

5.1 ReentrantLock

用法:

6. 信号量Semaphore

信号量,用来体现 可用资源的个数,本质上就是一个计数器。
  1. import java.util.concurrent.Semaphore;
  2. // 信号量 Semaphore
  3. public class ThreadDemo37 {
  4.     public static void main(String[] args) throws InterruptedException {
  5.         Semaphore semaphore = new Semaphore(1);
  6.         // 申请1个资源
  7.         semaphore.acquire();
  8.         System.out.println("P 操作");
  9.         semaphore.acquire();
  10.         System.out.println("P 操作");
  11.         // 释放一个资源
  12.         semaphore.release();
  13.         System.out.println("V 操作");
  14.     }
  15. }
复制代码

所谓的锁,本质上也是一种特殊的信号量,锁,可以认为计数值为1的信号量,开释状态,就是1,加锁状态,就是0,对于非0即1的信号量,称为二元信号量,信号量是更广义的锁
6.1 使用Semaphore可以包管线程安全,就相当于synchronized加锁

使用Semaphore,先申请一个资源然后举行下述count++操作,再举行开释操作,这样也可以确保线程安全
  1. import java.util.concurrent.Semaphore;
  2. // 信号量 Semaphore
  3. // 在操作前先申请一个可用资源 使数字-1 semaphore.acquire();  后semaphore.release(); 数字+1 释放一个可用资源
  4. // 加锁状态, 就是 0 ,释放状态,就是1 对于非0即1的信号量就称为 二元信号量
  5. public class ThreadDemo38 {
  6.     private static int count = 0;
  7.     public static void main(String[] args) throws InterruptedException {
  8.         Semaphore semaphore = new Semaphore(1);
  9.         Thread t1 = new Thread(() -> {
  10.             for (int i = 0; i < 50000; i++) {
  11.                 try {
  12.                     semaphore.acquire();
  13.                 } catch (InterruptedException e) {
  14.                     e.printStackTrace();
  15.                 }
  16.                 count++;
  17.                 semaphore.release();
  18.             }
  19.         });
  20.         Thread t2 = new Thread(() -> {
  21.             for (int i = 0; i < 50000; i++) {
  22.                 try {
  23.                     semaphore.acquire();
  24.                 } catch (InterruptedException e) {
  25.                     e.printStackTrace();
  26.                 }
  27.                 count++;
  28.                 semaphore.release();
  29.             }
  30.         });
  31.         t1.start();
  32.         t2.start();
  33.         t1.join();
  34.         t2.join();
  35.         System.out.println(count);
  36.     }
  37. }
复制代码
小结
确保线程安全的操作:
7. CountDownLatch

CountDownLatch,同时等待N个使命执行竣事,比如,多线程执行一个使命,把大的使命拆成几个部门,由每个线程分别执行

** join() ,就只能每个线程执行一个使命,而使用CountDownLatch就可以一个线程执行多个使命**。
  1. public class ThreadDemo39 {
  2.     public static void main(String[] args) throws InterruptedException {
  3.         // 1.此处构造方法中写10,意思是有10个线程任务
  4.         CountDownLatch latch = new CountDownLatch(10);
  5.         // 创建出 10个线程负责下载
  6.         for (int i = 0; i < 10; i++) {
  7.             int id = i;
  8.             Thread t = new Thread(() -> {
  9.                 Random random = new Random();
  10.                 int time = (random.nextInt(5) + 1) * 1000;
  11.                 System.out.println("线程 "+id+"开始下载");
  12.                 try {
  13.                     Thread.sleep(time);
  14.                 } catch (InterruptedException e) {
  15.                     e.printStackTrace();
  16.                 }
  17.                 System.out.println("线程结束 " + id + "结束下载");
  18.                 // 2.告知 CountDownLacth 执行结束了
  19.                 latch.countDown();
  20.             });
  21.             t.start();
  22.         }
  23.         // 3. 通过await操作等待所有任务结束,也就是 countDown被调用10次
  24.         latch.await();
  25.         System.out.println("所有任务都已经完成了");
  26.     }
  27. }
复制代码
8. ConcurrentHashMap

多线程环境下HashMap线程不安全,使用哈希表(Hashtable)就在关键方法上添加synchronized。

8.1 ConcurrentHashMap(Java1.8)的改进



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4