Java之多线程

线程是什么?

  • 进程: 程序运行时一块独立的内存空间
  • 线程: 内存中最小的执行单元
    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命令
Demo1为自己写的

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内存模型

  • 线程间共享了数据之后会发生什么
    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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值