Java多线程编程技巧 Java实现高效并发处理的几种方法

java多线程实现高效并发的关键在于合理使用线程池、锁机制、并发容器、原子操作和并发工具类。1. 线程池通过复用线程降低资源消耗,应根据任务类型选择fixedthreadpool、cachedthreadpool、singlethreadexecutor或scheduledthreadpool;2. 锁机制需优化选择,如synchronized适用于简单同步,reentrantlock提供更灵活控制,stampedlock适合读多写少场景,并需缩小锁范围、避免死锁;3. 并发容器如concurrenthashmap、copyonwritearraylist和concurrentlinkedqueue在高并发下性能更优;4. 原子类如atomicinteger基于cas实现无锁操作,适用于计数器等场景;5. 并发工具类countdownlatch、cyclicbarrier和semaphore协调线程协作。线程池大小应根据任务类型(cpu密集型设为核数或+1,io密集型考虑阻塞系数)和压测结果调整。避免死锁可通过一次性申请资源、可中断锁、资源有序分配等策略。性能瓶颈可通过减小锁粒度、读写分离、使用乐观锁和无锁结构缓解。高级并发技术如completablefuture实现异步编程,fork/join框架用于分治计算,响应式编程框架如reactor和rxjava提升吞吐量,适用于高并发、事件驱动场景。

Java多线程编程技巧 Java实现高效并发处理的几种方法

Java多线程实现高效并发,这事儿说起来简单,真做起来却是个大学问。核心在于你如何平衡资源、如何设计任务流,以及如何巧妙地运用Java提供的那些并发工具。它不是简单地把任务扔给几个线程并行跑就万事大吉,很多时候,不恰当的并发设计反而会带来性能灾难,比如死锁、活锁、资源耗尽,甚至比单线程跑得还慢。所以,关键在于理解并发的本质,然后有策略地选择和组合各种技术手段。

Java多线程编程技巧 Java实现高效并发处理的几种方法

解决方案

要实现高效并发,我们通常会从以下几个核心点入手:

1. 线程池的精妙运用直接new Thread()这种做法,在大多数生产环境中都是要避免的。频繁地创建和销毁线程开销巨大,而且难以控制并发数量,容易导致系统资源耗尽。线程池(java.util.concurrent.Executors框架)才是王道。它通过复用已存在的线程来执行任务,有效降低了资源消耗,并且提供了丰富的策略来管理任务队列和拒绝策略。

Java多线程编程技巧 Java实现高效并发处理的几种方法固定大小线程池 (FixedThreadPool): 适用于任务数量已知,且需要稳定并发度的场景。比如,你有一个固定数量的数据库连接池,就可以用它来限制同时访问数据库的线程数。缓存线程池 (CachedThreadPool): 适用于任务量波动大,且任务执行时间短的场景。它会根据需要创建新线程,如果线程空闲时间过长则会回收。用起来很方便,但如果任务处理速度跟不上任务提交速度,可能会创建大量线程,耗尽系统资源。单线程线程池 (SingleThreadExecutor): 确保所有任务都在一个线程中按顺序执行。这在需要保证任务顺序性,同时又想利用线程池管理机制的场景下很有用。定时任务线程池 (ScheduledThreadPool): 用于执行定时或周期性任务。

选择哪种池子,池子应该有多大,这都是学问。没有银弹,真的得看业务场景,甚至需要通过压测来调优。

立即进入“豆包AI人工智官网入口”;

立即学习“豆包AI人工智能在线问答入口”;

2. 锁机制的策略性选择与优化并发编程离不开锁,但锁用不好就是性能杀手。

Java多线程编程技巧 Java实现高效并发处理的几种方法synchronized关键字: 这是Java最基本的同步机制,简单易用。JVM层面做了很多优化,比如偏向锁、轻量级锁、自旋锁,在很多情况下性能并不差。但它的缺点是粒度粗,且无法中断等待、无法实现公平锁。ReentrantLock: java.util.concurrent.locks.ReentrantLock提供了比synchronized更灵活的功能,比如可中断的锁获取(tryLock()),公平锁(ReentrantLock(true)),以及与条件变量(Condition)的配合使用。当你需要更精细的控制,或者需要避免死锁时,它就显得很有用了。StampedLock (Java 8+): 这是读写锁的升级版,支持乐观读。在读多写少的场景下,它的性能远超ReentrantReadWriteLock。乐观读不需要获取读锁,直接读取数据,然后通过版本戳验证数据是否被修改。如果被修改了,再降级为悲观读锁。这玩意儿用起来稍微复杂一点,但性能提升是实打实的。

核心思想是:尽量缩小锁的范围(减小临界区),避免在锁内执行耗时操作。能用无锁(CAS)解决的,就别用锁。

3. 并发容器的优先使用Java并发包(java.util.concurrent)提供了大量线程安全的容器,比如ConcurrentHashMap, CopyOnWriteArrayList, ConcurrentLinkedQueue等。这些容器在设计时就考虑了高并发场景,性能通常远优于手动对ArrayListHashMap进行Collections.synchronizedXXX包装。

ConcurrentHashMap: 替代HashtableCollections.synchronizedMap(HashMap)。它采用分段锁(Java 7及以前)或CAS+Synchronized(Java 8)来提高并发度,读操作基本无锁。CopyOnWriteArrayList/CopyOnWriteArraySet: 适用于读多写少的场景。写操作时会复制一份底层数组,在新数组上修改,然后替换旧数组。虽然写操作开销大,但读操作是完全无锁的,非常快。ConcurrentLinkedQueue/ConcurrentLinkedDeque: 高效的无界非阻塞队列,基于CAS实现。

能用并发容器解决的问题,就别自己造轮子加锁了,那是给自己挖坑。

4. 原子操作与CASjava.util.concurrent.atomic包下的类,如AtomicInteger, AtomicLong, AtomicReference等,提供了基于CAS(Compare-And-Swap)指令的无锁原子操作。CAS是一种乐观锁机制,它不阻塞线程,而是通过硬件指令来保证操作的原子性。如果期望值与内存中的实际值相同,则进行更新,否则重试。在计数器、状态标志等简单场景下,使用原子类比加锁的开销小得多,性能也更好。

5. 并发工具类的协调java.util.concurrent包还提供了许多用于线程协作的工具类:

CountDownLatch: 允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。比如,你启动了10个子任务,主线程需要等待所有子任务都完成后才能继续。CyclicBarrier: 允许一组线程互相等待,直到所有线程都到达一个公共屏障点。这个屏障是可重用的。Semaphore: 一个计数信号量,用于控制同时访问特定资源的线程数量。比如,限制某个API的并发请求数。

这些工具就像是多线程协作的指挥棒,能让复杂的并发逻辑变得清晰可控,避免了手动使用wait()/notify()带来的复杂性和易错性。

如何选择合适的线程池类型和大小?

选择线程池类型和大小,确实是Java并发编程里一个让人头疼但又不得不面对的问题。这玩意儿没有一个放之四海而皆准的公式,更像是一门艺术,需要结合你的业务场景、系统资源和实际压测数据来反复权衡和调整。

1. 任务类型是核心考量

CPU密集型任务: 这种任务大部分时间都在进行计算,很少阻塞。如果你开的线程数远超CPU核心数,那么线程上下文切换的开销就会抵消并行带来的好处,甚至让性能下降。推荐策略: 核心线程数通常设为 CPU核数 + 1,或者直接等于 CPU核数。多出来的那个线程,是为了防止某个线程偶尔的页缺失或其他轻微阻塞。例子: 大量数据加密解密、复杂数学计算、图像处理等。IO密集型任务: 这种任务大部分时间都在等待I/O操作完成(比如读写文件、网络请求、数据库查询)。线程在等待时不会占用CPU,所以可以多开一些线程,让CPU在某个线程等待时去执行其他线程的任务。推荐策略: 核心线程数可以设为 CPU核数 * (1 + 阻塞系数)。阻塞系数通常在0.8到0.9之间,这需要根据实际I/O等待时间来估算。如果I/O等待时间很长,阻塞系数就高,可以开更多线程。例子: 大量数据库查询、网络爬虫、文件下载上传等。

2. 队列的选择与拒绝策略

队列类型:ArrayBlockingQueue:有界队列。当队列满时,新任务会被拒绝(根据拒绝策略)。这种队列可以有效防止OOM,但可能导致任务丢失。LinkedBlockingQueue:默认是无界队列。如果任务提交速度快于处理速度,可能会导致队列无限增长,最终OOM。但你也可以给它指定一个容量。SynchronousQueue:一个不存储元素的队列。每个插入操作必须等待另一个线程的移除操作。适用于任务提交和处理速度基本一致的场景。拒绝策略:AbortPolicy (默认):直接抛出RejectedExecutionExceptionCallerRunsPolicy:调用者线程执行任务。DiscardOldestPolicy:丢弃队列中最老的任务。DiscardPolicy:直接丢弃新任务。

我的经验是,对于大多数Web服务,IO密集型任务居多,线程池大小往往会比CPU核数大很多。但最重要的是,上线前一定要做充分的压测,监控CPU使用率、内存占用、线程数和任务响应时间。根据这些数据来微调你的线程池参数。一开始可以拍个经验值,但最终的参数一定是在实际负载下跑出来的。

锁机制在Java并发编程中如何避免死锁和性能瓶颈?

锁,是并发编程的基石,但也是最容易踩坑的地方。死锁和性能瓶颈,就像是悬在程序员头上的两把达摩克利斯之剑。

1. 避免死锁的策略

死锁的发生通常需要满足四个条件:互斥条件、请求与保持条件、不剥夺条件、循环等待条件。要避免死锁,我们通常需要破坏其中一个或多个条件。

破坏请求与保持条件:一次性申请所有资源

如果一个线程在持有某些资源的同时,又去请求其他资源,就有可能导致死锁。一个简单的策略是:线程在开始执行前,一次性获取所有它需要的锁。如果不能全部获取,就释放已经持有的锁,然后重新尝试。这可以用ReentrantLocktryLock()方法配合超时机制来实现。举例: 银行转账,A转账给B,需要同时锁定A和B的账户。如果先锁A再锁B,另一个线程先锁B再锁A,就可能死锁。正确的做法是,同时尝试获取A和B的锁,如果有一个没拿到,就全部释放重试。

破坏不剥夺条件:可中断锁

synchronized锁是不可中断的,一旦线程获取了锁,就必须等待它释放。但ReentrantLock提供了lockInterruptibly()方法,允许在等待锁的过程中响应中断。这意味着,如果一个线程长时间等待某个锁,你可以中断它,让它放弃等待,从而打破死锁循环。举例: 两个线程互相等待对方释放锁,这时可以中断其中一个线程,让它释放自己的锁,从而打破僵局。

破坏循环等待条件:资源有序分配

这是最常用也最有效的避免死锁的方法之一。给系统中的所有资源(比如锁)一个全局的顺序,线程在请求资源时,必须按照这个顺序来获取。举例: 如果有两个锁lockAlockB,规定线程必须先获取lockA,再获取lockB。这样就不会出现一个线程先拿lockA再拿lockB,而另一个线程先拿lockB再拿lockA的循环等待情况。

死锁是并发编程的噩梦,一旦出现排查起来会非常痛苦。遵循这些设计原则,或者使用一些高级的死锁检测工具,能大大降低风险。

2. 避免性能瓶颈的策略

减小锁粒度: 锁的范围越小,并发冲突的可能性就越低。分段锁: 比如ConcurrentHashMap就是通过将整个哈希表分成多个段,每个段一个锁,从而允许多个线程同时操作不同的段。细粒度锁定: 如果一个方法中只有一小部分代码需要同步,那就只对这部分代码加锁,而不是整个方法。读写分离:ReentrantReadWriteLock当你的数据结构读操作远多于写操作时,ReentrantReadWriteLock是个不错的选择。它允许多个读线程同时访问共享资源,但写操作依然是独占的。这显著提升了读操作的并发性能。乐观锁 vs 悲观锁:CAS传统锁是悲观锁,认为总会有冲突,所以先加锁。而CAS是乐观锁,认为冲突很少发生,所以先尝试操作,如果发现冲突再重试。在冲突率低的情况下,CAS的性能远优于悲观锁,因为它没有线程阻塞和上下文切换的开销。避免在锁内执行耗时操作:任何可能阻塞或长时间运行的操作(如网络I/O、文件I/O、复杂的数据库查询)都应该尽量移到锁的外部执行。锁住的时间越短,其他等待的线程就能越快地获得锁。使用无锁数据结构和算法:如果可能,优先使用java.util.concurrent包下的并发容器和原子类,它们通常比你自己手动加锁的实现更高效、更健壮。

性能瓶颈的优化,往往需要借助性能分析工具(如JProfiler, VisualVM)来定位热点代码和锁竞争点。没有数据支撑的优化,很多时候都是盲人摸象。

除了传统锁和线程池,还有哪些高级并发技术可以提升Java应用的吞吐量?

Java的并发世界远不止线程池和锁那么简单。随着Java版本的迭代,以及对高并发、低延迟需求的不断增长,出现了很多更高级、更抽象的并发模型和工具,它们能显著提升应用的吞吐量和响应能力。

1. CompletableFuture:异步编程的利器

CompletableFuture是Java 8引入的,它代表了一个异步计算的结果。这玩意儿极大地简化了异步编程,避免了传统回调地狱的窘境,让你可以以同步的方式来编写异步代码。

非阻塞: 任务提交后立即返回CompletableFuture对象,当前线程不会阻塞,可以继续执行其他任务。链式调用: 你可以轻松地将多个异步操作串联起来,比如thenApply(转换结果)、thenAccept(消费结果)、thenCombine(合并两个CompletableFuture的结果)、allOf(等待所有CompletableFuture完成)、anyOf(等待任意一个CompletableFuture完成)。异常处理: 提供统一的异常处理机制,如exceptionally

为什么提升吞吐量? 它让你的应用程序能够更有效地利用I/O等待时间。当一个任务需要等待I/O(比如调用远程服务、查询数据库)时,当前线程可以释放出来去处理其他任务,而不是傻傻地阻塞等待。这对于I/O密集型应用来说,是提高吞吐量的关键。

2. Fork/Join 框架:分治思想的实践

Fork/Join框架(java.util.concurrent.ForkJoinPool)是Java 7引入的,它基于“分治”(Divide and Conquer)思想,专门用于解决那些可以分解成更小、独立子任务的问题。

工作窃取(Work-Stealing): ForkJoinPool内部使用了一种工作窃取算法。当一个线程完成了自己的所有任务后,它会尝试从其他繁忙线程的双端队列的尾部“窃取”任务来执行。这使得所有工作线程都能保持忙碌,最大化CPU利用率。适用于大规模并行计算: 比如大数据量的排序、搜索、矩阵乘法等。

为什么提升吞吐量? Fork/Join框架能够充分利用多核CPU的优势,自动将大任务拆分并调度到可用的处理器核心上并行执行,从而显著缩短整体的执行时间,提升计算密集型任务的吞吐量。

3. 响应式编程框架 (Reactive Programming)

虽然不是Java标准库的一部分,但像Reactor、RxJava这样的响应式编程框架,正在成为处理高并发、事件驱动应用的主流选择。

事件流: 它们将数据和事件视为流,可以对这些流进行各种操作(过滤、转换、合并等)。非阻塞I/O: 天然支持非阻塞I/O,非常适合构建高吞吐量的网络服务。背压(Backpressure): 生产者不会以消费者无法处理的速度发送数据,从而避免了资源耗尽。

为什么提升吞吐量? 响应式编程模型通过异步、非阻塞的方式处理请求,避免了传统线程模型中大量的线程上下文切换和资源阻塞。它能够以更少的线程处理更多的并发请求,从而大幅提升系统的吞吐量和资源利用率。对于微服务架构、API网关等场景,响应式编程的优势尤为明显。

这些高级技术往往是解决特定场景下极致性能问题的关键。CompletableFuture让异步代码变得优雅,Fork/Join让分治算法的并行化变得简单,而响应式编程则彻底改变了我们处理事件流和I/O的方式。掌握它们,无疑会让你在构建高性能Java应用时如虎添翼。

以上就是Java多线程编程技巧 Java实现高效并发处理的几种方法的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/131761.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月28日 19:45:46
下一篇 2025年11月28日 20:10:41

相关推荐

  • CSS mask属性无法获取图片:为什么我的图片不见了?

    CSS mask属性无法获取图片 在使用CSS mask属性时,可能会遇到无法获取指定照片的情况。这个问题通常表现为: 网络面板中没有请求图片:尽管CSS代码中指定了图片地址,但网络面板中却找不到图片的请求记录。 问题原因: 此问题的可能原因是浏览器的兼容性问题。某些较旧版本的浏览器可能不支持CSS…

    2025年12月24日
    900
  • Uniapp 中如何不拉伸不裁剪地展示图片?

    灵活展示图片:如何不拉伸不裁剪 在界面设计中,常常需要以原尺寸展示用户上传的图片。本文将介绍一种在 uniapp 框架中实现该功能的简单方法。 对于不同尺寸的图片,可以采用以下处理方式: 极端宽高比:撑满屏幕宽度或高度,再等比缩放居中。非极端宽高比:居中显示,若能撑满则撑满。 然而,如果需要不拉伸不…

    2025年12月24日
    400
  • 如何让小说网站控制台显示乱码,同时网页内容正常显示?

    如何在不影响用户界面的情况下实现控制台乱码? 当在小说网站上下载小说时,大家可能会遇到一个问题:网站上的文本在网页内正常显示,但是在控制台中却是乱码。如何实现此类操作,从而在不影响用户界面(UI)的情况下保持控制台乱码呢? 答案在于使用自定义字体。网站可以通过在服务器端配置自定义字体,并通过在客户端…

    2025年12月24日
    800
  • SASS 中的 Mixins

    mixin 是 css 预处理器提供的工具,虽然它们不是可以被理解的函数,但它们的主要用途是重用代码。 不止一次,我们需要创建多个类来执行相同的操作,但更改单个值,例如字体大小的多个类。 .fs-10 { font-size: 10px;}.fs-20 { font-size: 20px;}.fs-…

    2025年12月24日
    000
  • 如何在地图上轻松创建气泡信息框?

    地图上气泡信息框的巧妙生成 地图上气泡信息框是一种常用的交互功能,它简便易用,能够为用户提供额外信息。本文将探讨如何借助地图库的功能轻松创建这一功能。 利用地图库的原生功能 大多数地图库,如高德地图,都提供了现成的信息窗体和右键菜单功能。这些功能可以通过以下途径实现: 高德地图 JS API 参考文…

    2025年12月24日
    400
  • 如何使用 scroll-behavior 属性实现元素scrollLeft变化时的平滑动画?

    如何实现元素scrollleft变化时的平滑动画效果? 在许多网页应用中,滚动容器的水平滚动条(scrollleft)需要频繁使用。为了让滚动动作更加自然,你希望给scrollleft的变化添加动画效果。 解决方案:scroll-behavior 属性 要实现scrollleft变化时的平滑动画效果…

    2025年12月24日
    000
  • 如何为滚动元素添加平滑过渡,使滚动条滑动时更自然流畅?

    给滚动元素平滑过渡 如何在滚动条属性(scrollleft)发生改变时为元素添加平滑的过渡效果? 解决方案:scroll-behavior 属性 为滚动容器设置 scroll-behavior 属性可以实现平滑滚动。 html 代码: click the button to slide right!…

    2025年12月24日
    500
  • 为什么设置 `overflow: hidden` 会导致 `inline-block` 元素错位?

    overflow 导致 inline-block 元素错位解析 当多个 inline-block 元素并列排列时,可能会出现错位显示的问题。这通常是由于其中一个元素设置了 overflow 属性引起的。 问题现象 在不设置 overflow 属性时,元素按预期显示在同一水平线上: 不设置 overf…

    2025年12月24日 好文分享
    400
  • 网页使用本地字体:为什么 CSS 代码中明明指定了“荆南麦圆体”,页面却仍然显示“微软雅黑”?

    网页中使用本地字体 本文将解答如何将本地安装字体应用到网页中,避免使用 src 属性直接引入字体文件。 问题: 想要在网页上使用已安装的“荆南麦圆体”字体,但 css 代码中将其置于第一位的“font-family”属性,页面仍显示“微软雅黑”字体。 立即学习“前端免费学习笔记(深入)”; 答案: …

    2025年12月24日
    000
  • 如何选择元素个数不固定的指定类名子元素?

    灵活选择元素个数不固定的指定类名子元素 在网页布局中,有时需要选择特定类名的子元素,但这些元素的数量并不固定。例如,下面这段 html 代码中,activebar 和 item 元素的数量均不固定: *n *n 如果需要选择第一个 item元素,可以使用 css 选择器 :nth-child()。该…

    2025年12月24日
    200
  • 使用 SVG 如何实现自定义宽度、间距和半径的虚线边框?

    使用 svg 实现自定义虚线边框 如何实现一个具有自定义宽度、间距和半径的虚线边框是一个常见的前端开发问题。传统的解决方案通常涉及使用 border-image 引入切片图片,但是这种方法存在引入外部资源、性能低下的缺点。 为了避免上述问题,可以使用 svg(可缩放矢量图形)来创建纯代码实现。一种方…

    2025年12月24日
    100
  • 如何让“元素跟随文本高度,而不是撑高父容器?

    如何让 元素跟随文本高度,而不是撑高父容器 在页面布局中,经常遇到父容器高度被子元素撑开的问题。在图例所示的案例中,父容器被较高的图片撑开,而文本的高度没有被考虑。本问答将提供纯css解决方案,让图片跟随文本高度,确保父容器的高度不会被图片影响。 解决方法 为了解决这个问题,需要将图片从文档流中脱离…

    2025年12月24日
    000
  • 为什么我的特定 DIV 在 Edge 浏览器中无法显示?

    特定 DIV 无法显示:用户代理样式表的困扰 当你在 Edge 浏览器中打开项目中的某个 div 时,却发现它无法正常显示,仔细检查样式后,发现是由用户代理样式表中的 display none 引起的。但你疑问的是,为什么会出现这样的样式表,而且只针对特定的 div? 背后的原因 用户代理样式表是由…

    2025年12月24日
    200
  • inline-block元素错位了,是为什么?

    inline-block元素错位背后的原因 inline-block元素是一种特殊类型的块级元素,它可以与其他元素行内排列。但是,在某些情况下,inline-block元素可能会出现错位显示的问题。 错位的原因 当inline-block元素设置了overflow:hidden属性时,它会影响元素的…

    2025年12月24日
    000
  • 为什么 CSS mask 属性未请求指定图片?

    解决 css mask 属性未请求图片的问题 在使用 css mask 属性时,指定了图片地址,但网络面板显示未请求获取该图片,这可能是由于浏览器兼容性问题造成的。 问题 如下代码所示: 立即学习“前端免费学习笔记(深入)”; icon [data-icon=”cloud”] { –icon-cl…

    2025年12月24日
    200
  • 为什么使用 inline-block 元素时会错位?

    inline-block 元素错位成因剖析 在使用 inline-block 元素时,可能会遇到它们错位显示的问题。如代码 demo 所示,当设置了 overflow 属性时,a 标签就会错位下沉,而未设置时却不会。 问题根源: overflow:hidden 属性影响了 inline-block …

    2025年12月24日
    000
  • 如何利用 CSS 选中激活标签并影响相邻元素的样式?

    如何利用 css 选中激活标签并影响相邻元素? 为了实现激活标签影响相邻元素的样式需求,可以通过 :has 选择器来实现。以下是如何具体操作: 对于激活标签相邻后的元素,可以在 css 中使用以下代码进行设置: li:has(+li.active) { border-radius: 0 0 10px…

    2025年12月24日
    100
  • 为什么我的 CSS 元素放大效果无法正常生效?

    css 设置元素放大效果的疑问解答 原提问者在尝试给元素添加 10em 字体大小和过渡效果后,未能在进入页面时看到放大效果。探究发现,原提问者将 CSS 代码直接写在页面中,导致放大效果无法触发。 解决办法如下: 将 CSS 样式写在一个单独的文件中,并使用 标签引入该样式文件。这个操作与原提问者观…

    2025年12月24日
    000
  • 如何模拟Windows 10 设置界面中的鼠标悬浮放大效果?

    win10设置界面的鼠标移动显示周边的样式(探照灯效果)的实现方式 在windows设置界面的鼠标悬浮效果中,光标周围会显示一个放大区域。在前端开发中,可以通过多种方式实现类似的效果。 使用css 使用css的transform和box-shadow属性。通过将transform: scale(1.…

    2025年12月24日
    200
  • 为什么我的 em 和 transition 设置后元素没有放大?

    元素设置 em 和 transition 后不放大 一个 youtube 视频中展示了设置 em 和 transition 的元素在页面加载后会放大,但同样的代码在提问者电脑上没有达到预期效果。 可能原因: 问题在于 css 代码的位置。在视频中,css 被放置在单独的文件中并通过 link 标签引…

    2025年12月24日
    100

发表回复

登录后才能评论
关注微信