Java线程从入门到实践

createh54周前 (04-07)技术教程5

Java线程杂谈:从入门到“放弃”?

大家好,今天我们来聊聊Java线程这个让人又爱又恨的话题。作为一个Java开发者,谁没在深夜里对着死锁日志抓狂过?谁没被
ConcurrentModificationException折磨得怀疑人生?今天我们就用轻松的方式,聊聊线程那些事儿。


一、线程的诞生:是继承Thread还是实现Runnable?

新手必问:"创建线程到底用继承Thread还是实现Runnable?"
答案很简单:优先选Runnable!为什么?

  1. Java单继承的枷锁:继承Thread后你的类就不能继承其他爹了
  2. 资源共享优势:多个线程可以共享同一个Runnable实例
  3. Lambda的魔法:new Thread(() -> System.out.println("真香")).start();

但面试官总爱追问:"那Callable和Future呢?"
悄悄告诉你:当需要返回值或抛异常时,它们才是真香组合!


二、线程状态:比女朋友的心情还复杂

线程的6种状态(别数了,Java定义的就是6种):

  1. NEW:刚new出来还没start的萌新
  2. RUNNABLE:在JVM眼里,就绪和运行都算runnable
  3. BLOCKED:拿着爱的号码牌等锁的苦主
  4. WAITING:望眼欲穿等唤醒的痴情种(wait/join)
  5. TIMED_WAITING:设了闹钟的等待(sleep(1000))
  6. TERMINATED:领盒饭退场

经典面试题:"sleep()和wait()的区别?"

  • sleep是Thread的静态方法,不释放锁
  • wait是Object的方法,释放锁还要被notify

三、同步的艺术:synchronized的千层套路

java

// 对象锁的三种姿势

public synchronized void method() {} // 等同于锁this

public void method() { synchronized(this) {} }

public void method() { synchronized(obj) {} }


// 类锁的正确打开方式

public static synchronized void staticMethod() {} // 锁Class对象

但synchronized太重了怎么办?
试试ReentrantLock的三大绝招:

  1. 可中断等待:lock.lockInterruptibly()
  2. 公平锁:new ReentrantLock(true)
  3. 条件变量:Condition condition = lock.newCondition()

四、线程池:别重复造轮子!

为什么要用线程池?看看这血泪史:

  1. 频繁创建/销毁线程开销大
  2. 不加管控的线程可能OOM
  3. 缺乏统一管理(拒绝策略、监控等)

Executor框架的四大天王:

java

复制


Executors.newCachedThreadPool(); // 线程数弹性伸缩


Executors.newFixedThreadPool(8); // 固定大小


Executors.newSingleThreadExecutor(); // 单线程串行执行


Executors.newScheduledThreadPool(3); // 定时任务专家

但阿里规约为什么不让直接用Executors?
因为默认队列无界可能OOM!推荐手动newThreadPoolExecutor,七参数配置更灵活。


五、并发工具包:JUC大法好

  1. CountDownLatch:老板等所有员工下班锁门

java

CountDownLatch latch = new CountDownLatch(3);

// 三个线程分别countDown()

latch.await(); // 阻塞直到计数器归零

  1. CyclicBarrier:旅游团集合点等人齐发车

java

CyclicBarrier barrier = new CyclicBarrier(5, ()->System.out.println("发车!"));

  1. Semaphore:海底捞等位区的叫号机

java

Semaphore semaphore = new Semaphore(5); // 5个许可

semaphore.acquire(); // 获取许可

semaphore.release();

  1. ConcurrentHashMap:线程安全的哈希表(比Hashtable高到不知哪里去了)

六、那些年我们踩过的坑

  1. 死锁现场

O 必要条件:互斥、占有且等待、不可抢占、循环等待

O 破局方法:jstack查线程栈,VisualVM在线监控

  1. 内存可见性

O volatile解决可见性问题(但不保证原子性)

O 经典案例:while(!stopFlag)可能永远不停止

  1. ThreadLocal的魔幻现实

O 每个线程独立副本

O 但用完要remove()!否则线程池复用会导致数据错乱


七、新世界大门:Java 8+的并发黑科技

  1. CompletableFuture:异步编程利器

java

CompletableFuture.supplyAsync(() -> "hello")

.thenApply(s -> s + " world")

.thenAccept(System.out::println);

  1. 并行流(Parallel Stream):一行代码实现并行处理

java

IntStream.range(1,100).parallel().sum();

  1. StampedLock:读写锁的升级版,乐观读锁提升性能

结语:多线程修炼指南

想要真正掌握Java并发,建议:

  1. 精读《Java并发编程实战》(虽然可能看三遍才懂)
  2. 多写demo,用jstack、VisualVM等工具分析
  3. 参与开源项目,看别人怎么写并发代码
  4. 牢记:没有银弹! 不同场景选择不同方案

最后送大家一句保命箴言:"能不用锁就别用,要用就用最小粒度的锁!"


互动话题:你遇到过最诡异的并发bug是什么?欢迎在评论区分享你的血泪史!

相关文章

面试必备之对象拷贝神器

BeanUtils.copyProperties vs BeanCopier:谁才是Java界的“复制粘贴之王”?1. 开篇:Java界的“复制粘贴”江湖在Java的世界里,对象的复制粘贴(属性拷贝)...

Java虚拟机的GC算法:标记-清除与复制

Java虚拟机的GC算法:标记-清除与复制在Java编程的世界里,垃 圾回收(Garbage Collection, GC)就像是一位默默工作的园丁,它清理着程序运行过程中不再需要的对象,为新生对象腾...

正确复制、重写别人的代码,不算抄袭

我最近在一篇文章提到,工程师应该怎样避免使用大量的库、包以及其他依赖关系。我建议的另一种方案是,如果你没有达到重用第三方代码的阈值时,那么你就可以自己编写代码。在本文中,我将讨论一个在重用和从头开始编...

Java程序员,一周Python入门:数组,元组,集合,集合,字典

今天来对比学习一下存储的方式。Java 和 Python 在数据结构方面有很多不同之处,特别是 列表(List)、元组(Tuple)、集合(Set)、字典(Dict/Map) 的使用方式。Python...