多线程(一) 线程的基本知识

一.线程和进程

 

进程:操作系统资源资源分配的基本单位,占用的资源较大,进程间无共享内存,切换进程时,cpu消耗太多

线程:任务调度和执行的基本单位,一个进程可以有多个线程,线程之间公用所在进程的内存,资源共享。创建线程的开销较小。

 

二.线程的生命周期

 

线程总共有6种状态,分别如下:

1.新建状态(NEW):当创建一个线程对象的时候,线程处于该状态。

2.运行状态(RUNABLE):当调用线程的start方法时,线程处于该状态。该状态下有2个不同的子状态,分别是可运行和运行状态,当cpu调度当前线程的时候,线程状态为可运行状态,当cpu放弃当前线程或者当前线程执行yield操作时,该线程会重新进入可运行状态,等待cpu调度。

3.等待状态(WAITING和TIME_WAITING):两个状态唯一的区别就是是否加上时间参数,通过调用sleep,join,wait等方法进入该状态。

4.阻塞状态(BLOCKED):只有在执行到synchronized代码块,没有获取到锁的时候,会变成阻塞状态。

5.结束状态(TERMINATED):当前线程执行结束。

 

三.线程的创建方式

 

1.继承Thread

2.实现Runnable接口

3.实现fature/callable接口,带返回值的线程

4.从线程池中获取

 

四.线程的中断

 

如何正确停止一个线程,在java中,有提供stop,destory,suspend,resume方法,但是这些方法都已经被不推荐使用了。原因是强行终止一个线程,可能会导致当前线程里面的资源没有来得及释放,比如锁等等。这样会导致程序出现异常。

那么如何优雅的停止线程呢,可以通过jdk提供的interrupt标示来实现,jdk在native中维护了interrupt标示来判断当前线程是否能够继续执行

案例1:线程内部通过isInterrupted方法判断是否中断,调用方通过interrupt方法终止指定线程

    public static void  test1() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                i++;
            }
            System.out.println("当前线程被中断,累计的和为:"+i);
        }, "t1");
        t1.start();
        TimeUnit.SECONDS.sleep(1);
        t1.interrupt();
    }

输出结果:

案例2:同样在调用方调用interrupt中断程序之后,然后在线程中执行Thread.interrupted()重新将标示改成false

 public static void  test2() throws InterruptedException {
        Thread t1 = new Thread(() -> {

            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("线程执行中。。。");
            }
            System.out.println("线程被中断");
            Thread.interrupted();

            System.out.println("线程中断标示复位,当前标志为:"+Thread.currentThread().isInterrupted());
        }, "t1");
        t1.start();
        TimeUnit.SECONDS.sleep(1);
        t1.interrupt();
    }

输出结果:

案例3:线程中catch了InterruptedException,然后在线程结束之前做一些资源处理

 public static void  test3() throws InterruptedException {
        Thread t1 = new Thread(() -> {

            while (true) {
                try {
                    System.out.println("线程执行中。。。");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("线程被中断");
                    System.out.println("对于中断之后抛出的异常可以进行相应的处理");
                }
            }
            }, "t1");
        t1.start();
        TimeUnit.SECONDS.sleep(1);
        t1.interrupt();

    }

 

五.查看当前线程状态

 

public class Test {

    public static void main(String[] args) {
        new Thread(() -> {
            while (true){
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"t1").start();


        new Thread(() -> {
            while (true){
                    synchronized (Test.class){
                        try {
                            //调用wait方法必须处于同步代码块中
                            Test.class.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

            }
        },"t2").start();

        new Thread(new BlockDemo(),"blocked-1").start();
        new Thread(new BlockDemo(),"blocked-2").start();
    }


    static class BlockDemo extends Thread{
        @Override
        public void run() {
            synchronized (BlockDemo.class){
                while (true){
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

进入命令行,输入jps查看所有正在进行的程序

当前正在测试的程序为Test,并且端口号为12320,执行命令jstack 12320查看该端口下所有线程的运行状态。

lingfandeMacBook-Pro:thread-demo lingfan$ jstack 12320
2019-09-23 20:15:25
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.131-b11 mixed mode):

"Attach Listener" #18 daemon prio=9 os_prio=31 tid=0x00007fc7dd003800 nid=0x5903 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"DestroyJavaVM" #17 prio=5 os_prio=31 tid=0x00007fc7dd9d6000 nid=0x1803 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"blocked-2" #16 prio=5 os_prio=31 tid=0x00007fc7dd9d5800 nid=0x5803 waiting for monitor entry [0x0000700006ae4000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at com.example.threaddemo.Test$BlockDemo.run(Test.java:47)
        - waiting to lock <0x000000076b157f78> (a java.lang.Class for com.example.threaddemo.Test$BlockDemo)
        at java.lang.Thread.run(Thread.java:748)

"blocked-1" #14 prio=5 os_prio=31 tid=0x00007fc7dc050000 nid=0xa603 waiting on condition [0x00007000069e1000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at java.lang.Thread.sleep(Thread.java:340)
        at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
        at com.example.threaddemo.Test$BlockDemo.run(Test.java:47)
        - locked <0x000000076b157f78> (a java.lang.Class for com.example.threaddemo.Test$BlockDemo)
        at java.lang.Thread.run(Thread.java:748)

"t2" #12 prio=5 os_prio=31 tid=0x00007fc7dd9a4800 nid=0xa803 in Object.wait() [0x00007000068de000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000076acec9f8> (a java.lang.Class for com.example.threaddemo.Test)
        at java.lang.Object.wait(Object.java:502)
        at com.example.threaddemo.Test.lambda$main$1(Test.java:27)
        - locked <0x000000076acec9f8> (a java.lang.Class for com.example.threaddemo.Test)
        at com.example.threaddemo.Test$$Lambda$2/1237514926.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

"t1" #11 prio=5 os_prio=31 tid=0x00007fc7dd002800 nid=0xa903 waiting on condition [0x00007000067db000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at java.lang.Thread.sleep(Thread.java:340)
        at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
        at com.example.threaddemo.Test.lambda$main$0(Test.java:15)
        at com.example.threaddemo.Test$$Lambda$1/625576447.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

"Service Thread" #10 daemon prio=9 os_prio=31 tid=0x00007fc7dd99f800 nid=0x4003 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread3" #9 daemon prio=9 os_prio=31 tid=0x00007fc7de008800 nid=0x4103 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread2" #8 daemon prio=9 os_prio=31 tid=0x00007fc7de008000 nid=0x4303 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #7 daemon prio=9 os_prio=31 tid=0x00007fc7dd99f000 nid=0x4503 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #6 daemon prio=9 os_prio=31 tid=0x00007fc7dd99e000 nid=0x4603 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Monitor Ctrl-Break" #5 daemon prio=5 os_prio=31 tid=0x00007fc7dd99c800 nid=0x3c03 runnable [0x00007000060c6000]
   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 <0x000000076adcb058> (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 <0x000000076adcb058> (a java.io.InputStreamReader)
        at java.io.BufferedReader.readLine(BufferedReader.java:389)
        at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64)

"Signal Dispatcher" #4 daemon prio=9 os_prio=31 tid=0x00007fc7df00a000 nid=0x3a03 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007fc7de80c800 nid=0x3503 in Object.wait() [0x0000700005ec0000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000076ab08ec8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
        - locked <0x000000076ab08ec8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"Reference Handler" #2 daemon prio=10 os_prio=31 tid=0x00007fc7de001000 nid=0x3403 in Object.wait() [0x0000700005dbd000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000076ab06b68> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:502)
        at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
        - locked <0x000000076ab06b68> (a java.lang.ref.Reference$Lock)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"VM Thread" os_prio=31 tid=0x00007fc7dd804000 nid=0x4f03 runnable 

t1线程执行sleep代码,状态为 java.lang.Thread.State: TIMED_WAITING (sleeping)。

t2线程执行wait代码,状态为   java.lang.Thread.State: WAITING (on object monitor)。

blocked-1线程抢夺到synchronized的锁,状态为   java.lang.Thread.State: TIMED_WAITING (sleeping)。
blocked-2线程没抢夺到synchronized的锁,状态为     java.lang.Thread.State: BLOCKED (on object monitor)。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值