核心内容摘要
破茧成蝶的暗夜琉璃:宁荣荣黑色吊带抹胸连衣裙的极致诱惑与时尚圣经
文章目录Java面试必看掌握线程同步与调度核心方法
线程同步为什么我们需要它
1 线程安全问题一场“多线程的灾难”代码示例线程不安全的计数器
2 解决方案同步机制
1.
1 synchronized关键字同步方法同步代码块
1.
2 ReentrantLock更灵活的同步工具示例代码
1.
3 选择合适的同步工具
线程调度如何让线程“有序”运行
1 线程的优先级高优先级 ≠ 总是先执行示例代码
2 线程间的通信wait()、notify()与notifyAll()示例代码生产者-消费者问题
3 CountDownLatch让多个线程“齐步走”示例代码
三、
总结通过合理使用这些机制可以有效管理多线程程序的行为避免常见的并发问题。
领取 | 1000 套高质量面试题大合集无套路闫工带你飞一把Java面试必看掌握线程同步与调度核心方法大家好我是闫工今天又是一个阳光明媚的日子不过看到你正在为Java面试而头疼闫工的心情也跟着阴沉了下来。
别担心闫工这就带着你踏上一场“线程同步与调度”的冒险之旅保证让你在面试中大放异彩
线程同步为什么我们需要它
1 线程安全问题一场“多线程的灾难”想象一下你正在食堂打饭多个同学同时排队买饭。
如果没有秩序大家可能会抢着拿同一个盘子导致食物洒得到处都是。
这就是典型的线程不安全问题在Java中线程安全问题主要表现为竞态条件Race Condition和内存可见性问题。
比如两个线程同时修改一个共享变量结果可能丢失其中一个修改。
代码示例线程不安全的计数器publicclassUnsafeCounter{privateintcount0;publicvoidincrement(){count;}publicstaticvoidmain(String[]args){UnsafeCountercounternewUnsafeCounter();Threadt1newThread(()-{for(inti0;i1000;i){counter.increment();}});Threadt2newThread(()-{for(inti0;i1000;i){counter.increment();}});t
start();t
start();try{t
join();t
join();}catch(InterruptedExceptione){e.printStackTrace();}System.out.println(最终计数counter.count);}}运行这段代码你会发现结果可能不是预期的2000。
这是因为两个线程同时操作同一个变量导致竞态条件。
2 解决方案同步机制
1.
1 synchronized关键字synchronized是Java中最常用的同步工具可以保证同一时间只有一个线程执行被加锁的代码块。
同步方法publicclassSafeCounter{privateintcount0;publicsynchronizedvoidincrement(){// 同步方法count;}}同步代码块publicclassSafeCounter2{privateintcount0;privatefinalObjectlocknewObject();// 私有锁对象publicvoidincrement(){synchronized(lock){// 使用自定义锁count;}}}
1.
2 ReentrantLock更灵活的同步工具ReentrantLock提供了比synchronized更灵活的功能比如可以中断锁等待、支持公平锁等。
示例代码importjava.util.concurrent.locks.ReentrantLock;publicclassSafeCounter3{privateintcount0;privateReentrantLocklocknewReentrantLock();publicvoidincrement(){lock.lock();// 尝试获取锁try{count;}finally{lock.unlock();// 释放锁}}}
1.
3 选择合适的同步工具如果需要简单的同步直接使用synchronized。
如果需要更灵活的功能比如公平锁、超时等待优先考虑ReentrantLock。
线程调度如何让线程“有序”运行
1 线程的优先级高优先级 ≠ 总是先执行Java中每个线程都有一个优先级范围为1到10。
虽然高优先级的线程更有可能被优先调度但具体行为还取决于JVM实现。
示例代码publicclassThreadPriorityDemo{publicstaticvoidmain(String[]args){Threadt1newThread(()-{System.out.println(低优先级线程开始);for(inti0;i5;i){System.out.println(Low thread: i);}System.out.println(低优先级线程结束);},LowThread);Threadt2newThread(()-{System.out.println(高优先级线程开始);for(inti0;i5;i){System.out.println(High thread: i);}System.out.println(高优先级线程结束);},HighThread);t
setPriority(Thread.MIN_PRIORITY);// 设置最低优先级t
setPriority(Thread.MAX_PRIORITY);// 设置最高优先级t
start();t
start();}}运行这段代码你会看到高优先级的线程可能先执行但结果并不总是如此。
2 线程间的通信wait()、notify()与notifyAll()有时候我们需要让一个线程等待另一个线程完成某些操作。
这时候wait()和notify()方法就派上了用场。
示例代码生产者-消费者问题importjava.util.Queue;importjava.util.concurrent.ConcurrentLinkedQueue;publicclassProducerConsumer{privateQueueStringqueuenewConcurrentLinkedQueue();privatefinalObjectlocknewObject();publicvoidproduce(Stringitem){synchronized(lock){// 加锁while(queue.size()
{// 模拟队列满的情况try{System.out.println(队列已满生产者等待...);lock.wait();// 等待消费者消费}catch(InterruptedExceptione){e.printStackTrace();}}queue.add(item);System.out.println(生产item);lock.notifyAll();// 唤醒所有可能在等待的线程}}publicvoidconsume(){synchronized(lock){// 加锁while(queue.isEmpty()){// 模拟队列空的情况try{System.out.println(队列为空消费者等待...);lock.wait();// 等待生产者生产}catch(InterruptedExceptione){e.printStackTrace();}}Stringitemqueue.poll();System.out.println(消费item);lock.notifyAll();// 唤醒所有可能在等待的线程}}publicstaticvoidmain(String[]args){ProducerConsumerpcnewProducerConsumer();Threadproducer1newThread(()-{for(inti0;i3;i){pc.produce(Product i);}},Producer
;Threadconsumer1newThread(()-{for(inti0;i5;i){pc.consume();}},Consumer
;producer
start();consumer
start();}}
3 CountDownLatch让多个线程“齐步走”CountDownLatch允许一个或多个线程等待直到其他指定的线程完成一系列操作。
示例代码importjava.util.concurrent.CountDownLatch;publicclassCountDownLatchDemo{publicstaticvoidmain(String[]args)throwsInterruptedException{intthreadCount3;CountDownLatchstartSignalnewCountDownLatch(
;// 所有线程等待开始信号CountDownLatchdoneSignalnewCountDownLatch(threadCount);// 主线程等待所有线程完成for(inti0;ithreadCount;i){ThreadworkernewThread(()-{try{System.out.println(线程准备就绪...);startSignal.await();// 等待开始信号doWork();doneSignal.countDown();// 完成后通知主线程}catch(InterruptedExceptione){e.printStackTrace();}});worker.start();}System.out.println(所有线程准备完毕即将开始...);startSignal.countDown();// 发送开始信号doneSignal.await();// 等待所有线程完成System.out.println(所有线程已完成任务);}privatestaticvoiddoWork(){System.out.println(Thread.currentThread().getName() 正在工作...);try{Thread.sleep(
;}catch(InterruptedExceptione){e.printStackTrace();}}}
三、
总结同步工具根据需求选择synchronized、ReentrantLock等。
线程调度优先级只能作为参考不能保证执行顺序。
线程通信使用wait()和notify()实现线程间的等待与唤醒。
复杂场景考虑使用更高阶的同步工具类如CountDownLatch、CyclicBarrier等。
通过合理使用这些机制可以有效管理多线程程序的行为避免常见的并发问题。
领取 | 1000 套高质量面试题大合集无套路闫工带你飞一把成体系的面试题无论你是大佬还是小白都需要一套JAVA体系的面试题我已经上岸了你也想上岸吗闫工精心准备了程序准备面试想系统提升技术实力闫工精心整理了1000 套涵盖前端、后端、算法、数据库、操作系统、网络、设计模式等方向的面试真题 详细解析并附赠高频考点