Java之多线程

    技术2025-06-13  20

    线程是什么?

    进程: 程序运行时一块独立的内存空间线程: 内存中最小的执行单元 ps:工作中基础的用不到,用到的是并发的工具类,线程池

    为什么要多进程

    进程之间调度起来,上下文切换,保留程序执行信息等,比较消耗资源,无法为多核CPU提供很好的支持 因此有了多线程,线程为CPU执行的单元,在切换时成本大大降低

    注: ‘’线程‘’,‘’进程‘’是计算机本身的概念。不是Java语言所特有的能力,其他语言也一样具有此能力。

    ps:面试:进程和线程的关系 tudo

    线程在Java中长什么样?

    Java是面向对象编程语言,所以Java将如何事物都抽象出了对象,线程也一样。在Java中线程类=Thread

    新建个运行的线程

    Thread thread = new Thread(); //新建thread.start(); //启动

    线程的生命周期 面试可能画这个图,画完后,状态如何切换说清楚。

    public class Demo1 { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() ->{ for (int i = 0; i <100000 ; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } }); t1.setName("kim"); //调了start之后,线程t1 进入就绪状态 t1.start(); //当cpu 切换到次线程时,才会进入到运行状态 Thread.sleep(1000*60*5); } }

    执行jsp命令

    jstack -l 26391 可看到gc,垃圾回收线程 Demo1定义的线程名称:kim,可以看到,#11就是

    localhost:~ cuihailong$ jstack -l 26457 2020-07-04 17:24:35 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.211-b12 mixed mode): "Attach Listener" #12 daemon prio=9 os_prio=31 tid=0x00007ff5c08fe800 nid=0x5703 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "kim" #11 prio=5 os_prio=31 tid=0x00007ff5c2054800 nid=0xa903 waiting on condition [0x000070000d299000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at course.basic.thread.Demo1.lambda$main$0(Demo1.java:12) at course.basic.thread.Demo1$$Lambda$1/883049899.run(Unknown Source) at java.lang.Thread.run(Thread.java:748) Locked ownable synchronizers: - None "Service Thread" #10 daemon prio=9 os_prio=31 tid=0x00007ff5c1800000 nid=0x3a03 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "C1 CompilerThread3" #9 daemon prio=9 os_prio=31 tid=0x00007ff5c1000800 nid=0x3803 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "C2 CompilerThread2" #8 daemon prio=9 os_prio=31 tid=0x00007ff5bf03d000 nid=0x3d03 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "C2 CompilerThread1" #7 daemon prio=9 os_prio=31 tid=0x00007ff5bf03c000 nid=0x3f03 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "C2 CompilerThread0" #6 daemon prio=9 os_prio=31 tid=0x00007ff5c201c800 nid=0x4103 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "Monitor Ctrl-Break" #5 daemon prio=5 os_prio=31 tid=0x00007ff5be024000 nid=0x3703 runnable [0x000070000cb84000] java.lang.Thread.State: RUNNABLE at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at java.net.SocketInputStream.read(SocketInputStream.java:171) at java.net.SocketInputStream.read(SocketInputStream.java:141) at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) - locked <0x000000079570dc68> (a java.io.InputStreamReader) at java.io.InputStreamReader.read(InputStreamReader.java:184) at java.io.BufferedReader.fill(BufferedReader.java:161) at java.io.BufferedReader.readLine(BufferedReader.java:324) - locked <0x000000079570dc68> (a java.io.InputStreamReader) at java.io.BufferedReader.readLine(BufferedReader.java:389) at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:61) Locked ownable synchronizers: - None "Signal Dispatcher" #4 daemon prio=9 os_prio=31 tid=0x00007ff5be021800 nid=0x3503 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007ff5be808800 nid=0x4803 in Object.wait() [0x000070000c97e000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x0000000795588ed0> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144) - locked <0x0000000795588ed0> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216) Locked ownable synchronizers: - None "Reference Handler" #2 daemon prio=10 os_prio=31 tid=0x00007ff5c181a000 nid=0x4a03 in Object.wait() [0x000070000c87b000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x0000000795586bf8> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:502) at java.lang.ref.Reference.tryHandlePending(Reference.java:191) - locked <0x0000000795586bf8> (a java.lang.ref.Reference$Lock) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153) Locked ownable synchronizers: - None "main" #1 prio=5 os_prio=31 tid=0x00007ff5c1801800 nid=0x1903 waiting on condition [0x000070000be5d000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at course.basic.thread.Demo1.main(Demo1.java:28) Locked ownable synchronizers: - None "VM Thread" os_prio=31 tid=0x00007ff5be003800 nid=0x2e03 runnable "GC task thread#0 (ParallelGC)" os_prio=31 tid=0x00007ff5c0807000 nid=0x1f07 runnable "GC task thread#1 (ParallelGC)" os_prio=31 tid=0x00007ff5c2000000 nid=0x2a03 runnable "GC task thread#2 (ParallelGC)" os_prio=31 tid=0x00007ff5c180a800 nid=0x5303 runnable "GC task thread#3 (ParallelGC)" os_prio=31 tid=0x00007ff5c180b000 nid=0x5103 runnable "GC task thread#4 (ParallelGC)" os_prio=31 tid=0x00007ff5be001800 nid=0x4f03 runnable "GC task thread#5 (ParallelGC)" os_prio=31 tid=0x00007ff5c180b800 nid=0x4d03 runnable "GC task thread#6 (ParallelGC)" os_prio=31 tid=0x00007ff5be002800 nid=0x2b03 runnable "GC task thread#7 (ParallelGC)" os_prio=31 tid=0x00007ff5be003000 nid=0x2c03 runnable "VM Periodic Task Thread" os_prio=31 tid=0x00007ff5bf03d800 nid=0x5503 waiting on condition JNI global references: 319 localhost:~ cuihailong$

    Runnable接口 Thread)(线程)常用方法

    start() 线程调用该方法将启动线程,使之从新建状态进入就绪队列排队,一旦轮到它来享用CPU资源时,就可以脱离创建它的线程独立开始自己的生命周期了 run() Thread类的run()方法与Runnable接口中的run()方法的功能和作用相同,都用来定义线程对象被调度之后所执行的操作,都是系统自动调用而用户程序不得引用的方法 sleep(int millsecond) 优先级高的线程可以在它的run()方法中调用sleep方法来使自己放弃CPU资源,休眠一段时间 isAlive() 线程处于“新建”状态时,线程调用isAlive()方法返回false。在线程的run()方法结束之前,即没有进入死亡状态之前,线程调用isAlive()方法返回true currentThread() 该方法是Thread类中的类方法,可以用类名调用,该方法返回当前正在使用CPU资源的线程 interrupt() 一个占有CPU资源的线程可以让休眠的线程调用interrupt()方法“吵醒”自己,即导致休眠的线程发生InterruptedException异常,从而结束休眠,重新排队等待CPU资源。 join() 作用是等待线程对象销毁主线程创建并启动了线程,如果子线程中要进行大量耗时运算,主线程往往将早于子线程结束之前结束。这时,如果主线程想等待子线程执行完成之后再结束,比如子线程处理一个数据,主线程要取得这个数据中的值,就要用到join()方法了。方法join()的作用是等待线程对象销毁 yield() 暂停当前正在执行的线程对象,并执行其他线程 setDaemon(boolean on) —守护线程 设置为后台线程 (启动线程前设置thread.setDaemon(True) 即 设置该线程为守护线程, 表示该线程是不重要的,进程退出时不需要等待这个线程执行完成。 这样做的意义在于:避免子线程无限死循环,导致退不出程序,也就是避免传说中的孤儿进程。)

    join例子

    public static void main(String[] args) throws InterruptedException { // Main Thread System.out.println("main start:" + LocalDateTime.now()); Thread t1 = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000 * 10); System.out.println("t1 finished:" + LocalDateTime.now()); } catch (InterruptedException e) { e.printStackTrace(); } } }); t1.setDaemon(true); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000 * 20); System.out.println("t2 finished:" + LocalDateTime.now()); } catch (InterruptedException e) { e.printStackTrace(); } } }); t2.setDaemon(true); t2.start(); t1.join(); t2.join(); System.out.println("main end:" + LocalDateTime.now()); }

    结果

    main start:2020-07-04T19:18:32.082 t1 finished:2020-07-04T19:18:42.088 t2 finished:2020-07-04T19:18:52.088 main end:2020-07-04T19:18:52.089 Process finished with exit code 0

    Java内存模型

    线程间共享了数据之后会发生什么

    线程安全问题

    出现原因: 由于内存数据的模型问题,导致多线程之间共享数据时会出现差异

    示例代码

    Integer data = 0; Object lock = new Object(); public static void main(String[] args) throws InterruptedException { Demo7 demo7 = new Demo7(); Thread t1 = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100; i++) { demo7.add(); } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100; i++) { demo7.sub(); } } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("demo7.data = " + demo7.data); } // 此时的锁是 new Demo7(); 这个 对象本身 // public synchronized void add() { // this.data++; // // /** // * 等同于 如下写法 // * synchronized (this) { // * this.data++; // * } // */ // } // // public synchronized void sub() { // this.data--; // } public void add() { synchronized (lock) { this.data++; } } public void sub() { synchronized (lock) { this.data--; } }

    结果

    demo7.data = 0
    Processed: 0.011, SQL: 9