• Java 线程详解


    本文主要介绍 Java 的 Thread 类一些用法。

    博主博客

    自定义测试类

    	private static class NukixThread extends Thread {
    		
    		public NukixThread(String name) {
    			super(name);
    		}
    
    		@Override
    		public void run() {
    			System.out.println("线程 ID: " + getId() + ", 线程名称: " + getName());
    		}
    	}
    

    一、isAlive、sleep、interrupt和isInterrupted

    isAlive: 判断线程是否存活。
    sleep: 使线程休眠指定的时间(毫秒)。
    interrupt: 中断线程的休眠状态, 比如令 sleep 抛出 InterruptedException 的异常。
    isInterrupted: 判断线程是否被中断。

    例子

    	NukixThread A = new NukixThread("A") {
    			@Override
    			public void run() {
    				super.run();
    				try {
    					Thread.sleep(1000);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				System.out.println("A 执行结束");
    			}
    		};
    		A.start();
    		
    		
    		NukixThread B = new NukixThread("B") {
    			@Override
    			public void run() {
    				super.run();
    				
    				for (int i = 0; i < 2; i++) {
    					// A.interrupt();
    					System.out.println("A.isAlive: " + A.isAlive() + ", A.isInterrupted: " + A.isInterrupted());
    					try {
    						Thread.sleep(5000);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    				System.out.println("B 执行结束");
    			}
    		};
    		B.start();
    

    输出

    线程 ID: 14, 线程名称: A
    线程 ID: 15, 线程名称: B
    A.isAlive: true, A.isInterrupted: false
    A 执行结束
    A.isAlive: false, A.isInterrupted: false
    B 执行结束
    

    当上面代码 A.interrupt(); 取消注释结果输出

    java.lang.InterruptedException: sleep interrupted
    线程 ID: 14, 线程名称: A
    线程 ID: 15, 线程名称: B
    A.isAlive: true, A.isInterrupted: false
    	at java.base/java.lang.Thread.sleep(Native Method)
    	at demo2.Main1$1.run(Main1.java:19)
    A 执行结束
    A.isAlive: false, A.isInterrupted: true
    B 执行结束
    

    二、wait、notify和notifyAll

    wait: 使当前线程进入等待状态, 并且让出锁, 需要通过 notify 或者 notifyAll 进行唤醒。
    notify: 唤醒正在等待的一个线程。
    notifyAll: 唤醒正在等待的所有线程。

    例子

    	private static final Object lock = new Object();
    	private static int count = 0;
    	
    	public static void main(String[] args) throws Exception {
    		
    		NukixThread A = new NukixThread("A") {
    			@Override
    			public void run() {
    				super.run();
    				
    				for (int i = 0; i < 3; i++) {
    					synchronized (lock) {
    						try {
    							lock.wait();
    						} catch (InterruptedException e) {
    							e.printStackTrace();
    						}
    					}
    					System.out.println(getName() + ": " + count++);
    					synchronized (lock) {
    						lock.notify();
    					}
    				}
    				
    				
    				
    				System.out.println("A 执行结束");
    			}
    		};
    		
    		NukixThread B = new NukixThread("B") {
    			@Override
    			public void run() {
    				super.run();
    				
    				for (int i = 0; i < 3; i++) {
    					synchronized (lock) {
    						try {
    							lock.wait();
    						} catch (InterruptedException e) {
    							e.printStackTrace();
    						}
    					}
    					System.out.println(getName() + ": " + count++);
    					synchronized (lock) {
    						lock.notify();
    					}
    				}
    				
    				System.out.println("B 执行结束");
    			}
    		};
    		
    		NukixThread C = new NukixThread("C") {
    			@Override
    			public void run() {
    				super.run();
    				
    				for (int i = 0; i < 3; i++) {
    					System.out.println(getName() + ": " + count++);
    					synchronized (lock) {
    						lock.notify();
    					}
    					
    					synchronized (lock) {
    						try {
    							lock.wait();
    						} catch (InterruptedException e) {
    							e.printStackTrace();
    						}
    					}
    				}
    				
    				System.out.println("C 执行结束");
    			}
    		};
    		
    		A.start();
    		B.start();
    		C.start();
    		
    	}
    

    输出

    线程 ID: 14, 线程名称: A
    线程 ID: 15, 线程名称: B
    线程 ID: 16, 线程名称: C
    C: 0
    A: 1
    B: 2
    C: 3
    A: 4
    B: 5
    C: 6
    A: 7
    A 执行结束
    B: 8
    B 执行结束
    C 执行结束
    

    从输出结果可以看出使用 notify 线程按照我们设定的 C->A->B 的顺序执行。 当我们把所有 notify 改成 notifyAll 会输出

    线程 ID: 14, 线程名称: A
    线程 ID: 16, 线程名称: C
    线程 ID: 15, 线程名称: B
    C: 0
    A: 1
    C: 2
    B: 3
    A: 4
    C: 5
    B: 6
    A: 7
    A 执行结束
    C 执行结束
    B: 8
    B 执行结束
    

    执行顺序会发生改变, 因为所有等待中的线程都被唤醒了。

    三、join

    join: 等待指定线程终止后继续运行。

    例子

    	NukixThread B = new NukixThread("B") {
    			@Override
    			public void run() {
    				super.run();
    				try {
    					Thread.sleep(5000);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				
    				System.out.println("B 执行结束");
    			}
    		};
    		
    		NukixThread A = new NukixThread("A") {
    			@Override
    			public void run() {
    				super.run();
    				
    				try {
    					Thread.sleep(1000);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				try {
    					B.join();
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				
    				System.out.println("A 执行结束");
    			}
    		};
    		
    		
    		A.start();
    		B.start();
    

    输出

    线程 ID: 15, 线程名称: A
    线程 ID: 14, 线程名称: B
    B 执行结束
    A 执行结束
    

    A 等待1秒, B 等待5秒, 正常情况应该 A 先结束。 但执行 B.join() 后, A 需要等到 B 执行完毕后才能继续执行。

    四、setDaemon和isDaemon

    setDaemon: 设置线程为守护线程
    isDaemon: 判断线程是否守护线程。

    例子

    	NukixThread B = new NukixThread("B") {
    			@Override
    			public void run() {
    				super.run();
    				for (int i = 0; i < 1000; i++) {
    					System.out.println("B 执行中: " + i + ", isDaemon: " + isDaemon());
    				}
    				
    				System.out.println("B 执行结束");
    			}
    		};
    		
    		NukixThread A = new NukixThread("A") {
    			@Override
    			public void run() {
    				super.run();
    				
    				B.start();
    				
    				try {
    					Thread.sleep(1);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				
    				System.out.println("A 执行结束");
    			}
    		};
    		
    		B.setDaemon(true);
    		A.start();
    

    输出

    线程 ID: 15, 线程名称: A
    线程 ID: 14, 线程名称: B
    B 执行中: 0, isDaemon: true
    B 执行中: 1, isDaemon: true
    ...
    A 执行结束
    ...
    B 执行中: 116, isDaemon: true
    

    可以看出, B 正常情况应该输出 999 但输出到 116 就已经不输出, 而且也没有输出执行结束, 程序已经停止。 因为 B 设置为守护线程, 用户线程(main线程、A线程)已经停止, 所以 守护线程 B 被迫停止了。

  • 相关阅读:
    微信测试号推送
    react源码分析:实现react时间分片
    家政上门系统源码,家政上门预约服务系统开发涉及的主要功能
    类和对象3:组合和混入
    qt 怎么实现在子窗体通知mainwindow界面发生改变
    如果我们是那晚负责修复 B 站崩了的开发人员
    vue3编译器原理
    工业相机飞拍模式介绍及相机曝光值计算
    【Spring Security 系列】(二)剖析基础组件之认证功能
    Docker镜像制作
  • 原文地址:https://blog.csdn.net/dxk539687357/article/details/127036695