尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

线程之通信

线程之通信 任何时候不管什么形式的锁只能被一个线程所持有。1.休眠唤醒方式之ObjectObject:wait、notify、notifyAll。注意必须在Synchronized同步锁–只能被一个线程拥有下使用线程进入锁之后调用wait方法并释放锁继续等待唤醒。另外一个线程获取锁之后调用notify释放锁并唤醒等待队列上的某个线程去竞争锁。等待线程唤醒之后继续执行执行完之后释放锁。2.休眠唤醒方式之ConditionLock方式加锁跟Synchronized一样。publicclassOrderDao{publicstaticvoidmain(String[]args){PersonpnewPerson();Threadt1newThread(p);t1.setName(t1);t1.start();Threadt2newThread(p);t2.setName(t2);t2.start();}}classPersonimplementsRunnable{LocklocknewReentrantLock();publicvoidrun(){//线程持有锁之后继续执行其他线程会一直等待锁的释放lock.lock();try{System.out.println(Thread.currentThread().getName()线程执行);}finally{System.out.println(Thread.currentThread().getName() 释放锁);lock.unlock();//释放锁之后被其他线程获取}}}Condition条件锁Synchronized关键字与wait()和notify/notifyAll()方法相结合可以实现等待/通知机制。ReentrantLock类当然也可以实现需要借助于Condition接口与newCondition() 方法。publicclassOrderDao{staticLocklocknewReentrantLock();staticConditionconditionlock.newCondition();staticprivateQueueStringqueuenewLinkedList();publicstaticvoidmain(String[]args){StringtaskgetTask();addTask(1);System.out.println(task);}publicstaticvoidaddTask(Strings){lock.lock();try{queue.add(s);condition.signalAll();}finally{lock.unlock();}}publicstaticStringgetTask(){//类似于Synchronized必须在锁机制下实现通信机制lock.lock();try{while(queue.isEmpty()){//等待的同时释放锁condition.await();}}catch(Exceptione){}finally{lock.unlock();}returnqueue.remove();}}3.CyclicBarrier一组线程等待至某个状态后再全部同时执行//构造入参一定与线程数相等,确定该组线程的个数privateCyclicBarrierbarriernewCyclicBarrier(3);publicstaticvoidmain(String[]args){finalOrderDaobarrierTestnewOrderDao();newThread(newRunnable(){publicvoidrun(){barrierTest.startThread();}},A).start();newThread(newRunnable(){publicvoidrun(){barrierTest.startThread();}},B).start();newThread(newRunnable(){publicvoidrun(){barrierTest.startThread();}},C).start();}publicvoidstartThread(){//1、打印线程准备启动StringnameThread.currentThread().getName();System.out.println(name正在准备...);//2、调用CyclicBarrier的await方法等待线程全部准备完成try{barrier.await();//等待所有线程准备完毕才继续执行}catch(Exceptione){// TODO Auto-generated catch blocke.printStackTrace();}//打印线程启动完毕信息System.out.println(name已经启动完毕newDate().getTime());}4.Semaphore用于控制对某组资源的访问权限semaphore个数未必与线程数相等只有当前线程能获取到semaphore就继续执行否则处于等待状态直到其他线程释放完毕publicstaticvoidmain(String[]args){intworks8;SemaphoresemaphorenewSemaphore(2);for(inti0;iworks;i){newThread(newWork(1,semaphore)).start();;}}staticclassWorkimplementsRunnable{privateintwokers;//工人数privateSemaphoresemaphores;//机器数publicWork(intworks,Semaphoresemaphore){this.semaphoressemaphore;this.wokersworks;}publicvoidrun(){try{//1、工人获取机器semaphores.acquire();//2、打印工人获取到的机器开始工作StringnameThread.currentThread().getName();System.out.println(name获取到机器开始工作...);//3、线程睡眠1秒模拟工人使用机器过程TimeUnit.SECONDS.sleep(5);//4、使用完毕释放机器打印工人使用完毕释放机器semaphores.release();System.out.println(name使用完毕,释放机器);}catch(InterruptedExceptione){// TODO Auto-generated catch blocke.printStackTrace();}}}阻塞任意线程发生阻塞后该线程自身停止执行无法处理任何新任务其他线程能否正常运行取决于阻塞类型。线程状态与 CPU 占用、是否释放 CPU1.BLOCKED / WAITING / TIMED_WAITING标准阻塞三态触发场景synchronized 抢锁失败、sleep、Object.wait、LockSupport.park、thread.join、BlockingQueue.take/poll、Condition.await。特性一定会释放 CPU线程 CPU 占用为 0操作系统挂起线程。2.RUNNABLE 分两种完全不同情况占用 CPU、不释放纯计算死循环、业务无 sleep 轮询自旋、AQS 短时自旋阶段持续抢占 CPU 时间片线程 CPU 使用率高。不占用 CPU、已释放同步网络 / 文件 / 数据库 IO 阻塞JVM 标记 RUNNABLE但内核阻塞挂起线程 CPU 占用 0。特殊AQS 锁竞争先自旋占 CPU自旋超时后 park 进入 WAITING 释放 CPU。不同阻塞对其他线程的影响IO/sleep/wait/park 类内核阻塞仅当前线程暂停所有其他线程不受影响正常调度运行。synchronized/Lock 锁阻塞仅竞争同一把锁的线程排队阻塞不竞争该锁的线程可正常执行。CPU 自旋 / 死循环持续占用 CPU 核心整体应用所有线程调度变慢、响应卡顿。线程池全部被阻塞任务占满新任务进入队列排队无法分配线程执行。如何判断线程是否正在占用 CPU仅看 JVM 线程状态不可靠判定标准BLOCKED/WAITING/TIMED_WAITING → 一定不占用 CPURUNNABLE 操作系统线程高 CPU 使用率 → 正在占用 CPURUNNABLE 线程 CPU 占用 0 → IO 阻塞已释放 CPU。排查工具top -Hp定位高 CPU 线程转 16 进制 nid 后用jstack匹配代码栈Arthasthread -n一键查看线程 CPU 与堆栈。
返回列表