热门面试题——多线程(源码案例详解)

简介: 热门面试题——多线程(源码案例详解)

问题一:写一个程序,证明AtomicInteger类比synchronized更高效

synchronized更高效
案例一

package duoxiancheng2;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author yeqv
 * @program A2
 * @Classname Ms4
 * @Date 2022/2/7 20:04
 * @Email w16638771062@163.com
 */
public class Ms4 {

    AtomicInteger n = new AtomicInteger(10000);
    int num = 10000;

    public static void main(String[] args) {

        var t = new Ms4();
        new Thread(t::minus, "T1").start();
        new Thread(t::minus, "T2").start();
        new Thread(t::minus, "T3").start();
        new Thread(t::minus, "T4").start();
        new Thread(t::minus, "T5").start();
        new Thread(t::minus, "T6").start();
        new Thread(t::minus, "T7").start();
        new Thread(t::minus, "T8").start();

    }

    void minus() {
        var a = System.currentTimeMillis();
        while (true) {
           /* if (n.get() > 0) {
                n.decrementAndGet();
                System.out.printf("%s 售出一张票,剩余%d张票。 %n", Thread.currentThread().getName(), n.get());
            } else {
                break;
            }*/
            synchronized (this) {
                if (num > 0) {
                    num--;
                    System.out.printf("%s 售出一张票,剩余%d张票。 %n", Thread.currentThread().getName(), num);
                } else {
                    break;
                }


            }


        }
        var b = System.currentTimeMillis();
        System.out.println(b - a);
    }
}

synchronized结果:
在这里插入图片描述
AtomicInteger结果:
在这里插入图片描述

问题二:写一个程序证明AtomXXX类的多个方法并不构成原子性

package demo16;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 写一个程序证明AtomXXX类的多个方法并不构成原子性
 */
public class T {
    AtomicInteger count = new AtomicInteger(0);

    void m() {
        for (int i = 0; i < 10000; i++) {
            if (count.get() < 100 && count.get() >= 0) { //如果未加锁,之间还会有其他线程插进来
                count.incrementAndGet();
            }
        }
    }

    public static void main(String[] args) {
        T t = new T();
        List<Thread> threads = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            threads.add(new Thread(t::m, "thread" + i));
        }
        threads.forEach(Thread::start);
        threads.forEach((o) -> {
            try {
                //join()方法阻塞调用此方法的线程,直到线程t完成,此线程再继续。通常用于在main()主线程内,等待其它线程完成再结束main()主线程。
                o.join(); //相当于在main线程中同步o线程,o执行完了,main线程才有执行的机会
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println(t.count);
    }
}

**

问题三:写一个程序,在main线程中启动100个线程,100个线程完成后,主线程打印“完成”

package cn.thread;

import java.util.concurrent.CountDownLatch;

/**
 * 写一个程序,在main线程中启动100个线程,100个线程完成后,主线程打印“完成”
 *
 * @author webrx [webrx@126.com]
 * @version 1.0
 * @since 16
 */
public class T12 {
    public static void main(String[] args) {
        CountDownLatch latch = new CountDownLatch(100);
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                String tn = Thread.currentThread().getName();
                System.out.printf("%s : 开始执行...%n", tn);
                System.out.printf("%s : 执行完成,程序结束。%n", tn);
                latch.countDown();
            }, "T" + i).start();
        }

        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("---------------------------------------");
        System.out.println("100个线程执行完了。");
        String tn = Thread.currentThread().getName();
        System.out.printf("%s : 执行完成,程序结束。%n", tn);
    }
}
相关文章
|
7天前
|
存储 缓存 Java
什么是线程池?从底层源码入手,深度解析线程池的工作原理
本文从底层源码入手,深度解析ThreadPoolExecutor底层源码,包括其核心字段、内部类和重要方法,另外对Executors工具类下的四种自带线程池源码进行解释。 阅读本文后,可以对线程池的工作原理、七大参数、生命周期、拒绝策略等内容拥有更深入的认识。
什么是线程池?从底层源码入手,深度解析线程池的工作原理
|
7天前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
|
7天前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
9天前
|
消息中间件 前端开发 NoSQL
面试官:线程池遇到未处理的异常会崩溃吗?
面试官:线程池遇到未处理的异常会崩溃吗?
42 3
面试官:线程池遇到未处理的异常会崩溃吗?
|
9天前
|
消息中间件 存储 前端开发
面试官:说说停止线程池的执行流程?
面试官:说说停止线程池的执行流程?
29 2
面试官:说说停止线程池的执行流程?
|
13天前
|
消息中间件 前端开发 NoSQL
面试官:如何实现线程池任务编排?
面试官:如何实现线程池任务编排?
22 1
面试官:如何实现线程池任务编排?
|
1月前
|
Java
【多线程面试题二十五】、说说你对AQS的理解
这篇文章阐述了对Java中的AbstractQueuedSynchronizer(AQS)的理解,AQS是一个用于构建锁和其他同步组件的框架,它通过维护同步状态和FIFO等待队列,以及线程的阻塞与唤醒机制,来实现同步器的高效管理,并且可以通过实现特定的方法来自定义同步组件的行为。
【多线程面试题二十五】、说说你对AQS的理解
|
1月前
|
Java
【多线程面试题十六】、谈谈ReentrantLock的实现原理
这篇文章解释了`ReentrantLock`的实现原理,它基于Java中的`AbstractQueuedSynchronizer`(AQS)构建,通过重写AQS的`tryAcquire`和`tryRelease`方法来实现锁的获取与释放,并详细描述了AQS内部的同步队列和条件队列以及独占模式的工作原理。
【多线程面试题十六】、谈谈ReentrantLock的实现原理
|
1月前
|
消息中间件 缓存 算法
Java多线程面试题总结(上)
进程和线程是操作系统管理程序执行的基本单位,二者有明显区别: 1. **定义与基本单位**:进程是资源分配的基本单位,拥有独立的内存空间;线程是调度和执行的基本单位,共享所属进程的资源。 2. **独立性与资源共享**:进程间相互独立,通信需显式机制;线程共享进程资源,通信更直接快捷。 3. **管理与调度**:进程管理复杂,线程管理更灵活。 4. **并发与并行**:进程并发执行,提高资源利用率;线程不仅并发还能并行执行,提升执行效率。 5. **健壮性**:进程更健壮,一个进程崩溃不影响其他进程;线程崩溃可能导致整个进程崩溃。
34 2
|
1月前
|
存储 安全 容器
【多线程面试题二十一】、 分段锁是怎么实现的?
这篇文章解释了分段锁的概念和实现方式,通过将数据分成多个段并在每段数据上使用独立锁,从而降低锁竞争,提高并发访问效率,举例说明了`ConcurrentHashMap`如何使用分段锁技术来实现高并发和线程安全。
【多线程面试题二十一】、 分段锁是怎么实现的?