1、Java多线程技能基础

news2024/11/15 9:53:55

文章目录

  • 第一章 Java多线程技能
    • 1.1进程和线程的定义以及多线程的优点
    • 1.2 使用多线程
      • 1.2.1继承Thread类
      • 1.2.2常见的3个命令分析线程的信息
        • 方法一\:cmd+jsp
        • 方法二\:jmc.exe
        • 方法三:jvisualcm.exe
      • 1.2.3 线程随机性的展现
      • 1.2.4 执行start()的顺序不代表执行run()的顺序
      • 1.2.5 实现Runnable接口
      • 1.2.6 使用Runnable接口实现多线程的优点
      • 1.2.7 public Thread(Runnable target)中的target参数
      • 1.2.8 实例变量共享导致的“非线程安全”问题与相应的解决方案
        • 1、不共享数据的情况
        • 2、共享数据的情况
      • 1.2.9 Servlet技术也会引起“非线程安全”问题
      • 1.2.10 留意i--与System.out.println()出现的“非线程安全”问题
      • 1.2.11 方法run()被JVM所调用
    • 1.3 方法currentThread()
    • 1.4 方法isAlive()
      • 关于Thread.currentThread().getName() 和 this.getName()区别详解
        • currentThread的详解
        • ****为什么为main呢**?**
        • 创建一个新的线程
    • 1.5 方法sleep(long millis)
    • 1.6 方法sleep(long millis, int nanos)
    • 1.7 方法StackTraceElement[] getStackTrace()
    • 1.8 方法static void dumpStack()
    • 1.9 方法Map<Thread, StackTraceElement[]> getAllStackTraces()
    • 1.10 方法getId()
    • 11.1 停止线程
      • 11.1.1 停止不了的线程
      • 11.1.2 判断是不是停止状态
      • 1.11.3 清除中断状态的使用场景
      • 1.11.4 能停止的线程——异常法
      • 1.11.5 在sleep状态下停止
      • 1.11.6 使用stop()暴力停止线程
      • 1.11.7 方法stop()与java.lang.ThreadDeath
      • 1.11.8 使用stop()释放锁导致数据结果不一致
      • 1.11.9 使用return;语句停止线程的缺点及相应解决方案
    • 1.12 暂停线程
      • 1.12.2 suspend()与resume()方法的缺点:独占
      • 1.12.3 suspend()与resume()方法的缺点:数据不完整
      • 1.12.4 使用LockSupport类实现线程的暂停恢复
    • 1.13 方法yield()
    • 1.14 线程的优先级
      • 1.14.1 线程优先级的继承特性
    • 1.14.2 线程优先级的规律性
      • 1.14.3 线程优先级的随机性
    • 1.15 守护线程
    • 1.16 并发与并行
    • 1.17 同步和异步
    • 1.18 多核CPU不一定比单核CPU运行的快

第一章 Java多线程技能

1.1进程和线程的定义以及多线程的优点

  1. 什么是线程:
    进程中独立运行的主任务
    (比如:在QQ运行中其他子任务也在运行)
    进程负责向操作系统申请资源

  2. 进程和线程的总结

  • 进程虽然是互相独立的,但他们可以互相通信,较为通用的方式为Socket和Http协议
  • 进程拥有共享的系统资源
  • 进程较重,因为创建进程需要操作系统分配资源,会占用内存
  • 线程存在于进程中,是进程的一个子集,先有进程,后有线程
  • 虽然线程更轻,但线程的上下文切换的时间成本非常高
  1. 什么场景需要多线程技术
  • 阻塞:一旦系统出现阻塞现象,则可以根据实际情况使用多线程提升运行效率
  • 依赖:业务分为两个执行结果(A,B),当b不依赖a业务执行的结果时,可以采用多线程

1.2 使用多线程

    public class Test {
        public static void main(String[] args) {
            System.out.println(Thread.currentThread().getName());
        }
    }

在这里插入图片描述
在控制台输出的main其实就是一个名称为main的线程在执行main()方法中的代码,main线程由JVM创建。另外需要说明一下,在控制台输出的main和main方法没有任何关系,它们仅仅是名字相同而已。

1.2.1继承Thread类

实现多线程编程的方式主要有两种:一种是继承Thread类,另外一种是实现Runnable接口。

Thread类的结构构成:

    public class Thread implements Runnable

例:

    public class MyThread extends Thread{
        public void run(){
            super.run();
            System.out.println("MyThread");
        }
    }

<!---->

    public class Run {
        public static void main(String[] args) {
            MyThread myThread=new MyThread();
            myThread.start();//耗时大
            System.out.println("运行结束");//耗时小
        }
    }

在这里插入图片描述

方法start()耗时多的原因是内部执行了多个步骤,步骤如下:

  1. 通过JVM告诉操作系统创建Thread;
  2. 操作系统开辟内存并使用Windows SDK中的createThread()函数创建Thread线程对象;
  3. 操作系统对Thread对象进行调度,以确定执行时机;
  4. Thread在操作系统中被成功执行。
    public class Run2 {
        public static void main(String[] args) throws InterruptedException {
            MyThread mythread = new MyThread();
            mythread.start();
            Thread.sleep(200);
            System.out.println("运行结束!");
        }

在这里插入图片描述

Thread.sleep()方法的参数是毫秒,代码可读性不好,而TimeUnit可以更加方便地使用指定的时间单位实现sleep操作,代码可读性好。其他时间单位为NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS、MINUTES、HOURS、DAYS。

    public class Run2 {
        public static void main(String[] args) throws InterruptedException {
            MyThread mythread = new MyThread();
            mythread.start();
            System.out.println("开始时间"+System.currentTimeMillis());
            TimeUnit.SECONDS.sleep(5);
            System.out.println("运行结束!");
            System.out.println("结束时间"+System.currentTimeMillis());
        }
    }

1.2.2常见的3个命令分析线程的信息

方法一:cmd+jsp

方法二:jmc.exe

下载地址:https://jdk.java.net/jmc/8/

方法三:jvisualcm.exe

在JDK1.6后的版本是自带这个工具,它就在你的jdk的bin目录上
在这里插入图片描述

1.2.3 线程随机性的展现

    public class MyThread extends Thread{
        public void run() {
            for (int i = 0; i < 10000; i++) {
                System.out.println("run=" + Thread.currentThread().getName());
            }
        }
    }

<!---->

    public class Test {
        public static void main(String[] args) {
            MyThread thread = new MyThread();
            thread.setName("myThread");
            thread.start();

            for (int i = 0; i < 10000; i++) {
                System.out.println("main=" + Thread.currentThread().getName());
            }
        }
    }

在这里插入图片描述

多线程随机输出的原因是CPU将时间片分给不同的线程,线程获得时间片后就执行任务,所以这些线程在交替执行并输出,导致输出结果呈乱序。

CPU在不同的线程上进行切换时是需要耗时的,所以并不是创建的线程越多,软件运行效率就越快,相反,线程数过多反而会降低软件的执行效率。

1.2.4 执行start()的顺序不代表执行run()的顺序

    public class MyThread extends Thread{
        private int i;

        public MyThread(int i) {
            super();
            this.i = i;
        }
        @Override
        public void run() {
            System.out.println(i);
        }
    }

<!---->

    public class Test {
        public static void main(String[] args) {
            MyThread t11 = new MyThread(1);
            MyThread t12 = new MyThread(2);
            MyThread t13 = new MyThread(3);
            MyThread t14 = new MyThread(4);
            MyThread t15 = new MyThread(5);
            MyThread t16 = new MyThread(6);
            MyThread t17 = new MyThread(7);
            MyThread t18 = new MyThread(8);
            MyThread t19 = new MyThread(9);
            MyThread t110 = new MyThread(10);
            MyThread t111 = new MyThread(11);
            MyThread t112 = new MyThread(12);
            MyThread t113 = new MyThread(13);

            t11.start();
            t12.start();
            t13.start();
            t14.start();
            t15.start();
            t16.start();
            t17.start();
            t18.start();
            t19.start();
            t110.start();
            t111.start();
            t112.start();
            t113.start();
        }
    }

在这里插入图片描述

1.2.5 实现Runnable接口

和Thread基本一样,为异步执行

    public class MyRunnable implements Runnable{
        @Override
        public void run() {
            System.out.println("运行中");
        }
    }

    package org.example.第一章Java多线程技能.N02使用多线程.N05实现Runnable接口;
    public class Run {
        public static void main(String[] args) {
            Runnable runnable=new MyRunnable();
            Thread thread=new Thread(runnable);
            thread.start();
            System.out.println("运行结束!");
        }
    }

在这里插入图片描述

1.2.6 使用Runnable接口实现多线程的优点

使用继承Thread类的方式来开发多线程应用程序在设计上是有局限的,因为==Java是单继承,不支持多继承,所以为了改变这种限制,可以使用实现Runnable接口的方式来实现多线程

    package org.example.第一章Java多线程技能.N02使用多线程.N06使用Runnable接口实现多线程的优点;

    public class AServer {
        public void a_save_method() {
            System.out.println("a中的保存数据方法被执行");
        }
    }

package org.example.第一章Java多线程技能.N02使用多线程.N06使用Runnable接口实现多线程的优点;
 public class BServer1 extends AServer implements Runnable {
     public void b_save_method() {
            System.out.println("b中的保存数据方法被执行");
        }

     @Override
     public void run() {
         a_save_method();
         b_save_method();
     }
 }

    package org.example.第一章Java多线程技能.N02使用多线程.N06使用Runnable接口实现多线程的优点;

    public class Test {
        public static void main(String[] args) {
            BServer1 bServer1=new BServer1();
            bServer1.run();
        }
    }

在这里插入图片描述

1.2.7 public Thread(Runnable target)中的target参数

Thread下的run方法:
在这里插入图片描述

target属性为Runnable:

在这里插入图片描述

1.2.8 实例变量共享导致的“非线程安全”问题与相应的解决方案

1、不共享数据的情况

    package org.example.第一章Java多线程技能.N02使用多线程.N08实例变量共享导致的非线程安全问题与相应的解决方案;

    public class MyThread extends Thread{
        private int count=5;
        public MyThread(String name){
            super();
            this.setName(name);//设置线程名称
        }

        @Override
        public void run() {
            super.run();
            while (count>0){
                count--;
                System.out.println("由 " + this.currentThread().getName() + " 计算,count=" + count);
            }
        }
    }

<!---->
    package org.example.第一章Java多线程技能.N02使用多线程.N08实例变量共享导致的非线程安全问题与相应的解决方案;

    public class Run {
        public static void main(String[] args) {
            MyThread a=new MyThread("A");
            MyThread b=new MyThread("B");
            MyThread c=new MyThread("C");
            a.start();
            b.start();
            c.start();

        }
    }

在这里插入图片描述

一共创建了3个线程,每个线程都有各自的count变量,自己减少自己的count变量的值

2、共享数据的情况

package org.example.第一章Java多线程技能.N02使用多线程.N08实例变量共享导致的非线程安全问题与相应的解决方案;
    public class MyThread2 extends Thread{
        int count=5;


        @Override
        public void run() {
            super.run();
            count--;
            // 此示例不要用while语句,会造成其他线程得不到运行的机会
            // 因为第一个执行while语句的线程会将count值减到0
            // 一直由一个线程进行减法运算
            System.out.println("由 "+this.currentThread().getName()+" 计算,count="+ count);
        }
    }


    package org.example.第一章Java多线程技能.N02使用多线程.N08实例变量共享导致的非线程安全问题与相应的解决方案;

    public class Run2 {
        public static void main(String[] args) {
            MyThread2 myThread2=new MyThread2();
            Thread a=new Thread(myThread2,"A");
            Thread b=new Thread(myThread2,"B");
            Thread c=new Thread(myThread2,"C");
            Thread d=new Thread(myThread2,"D");
            Thread e=new Thread(myThread2,"E");

            a.start();
            b.start();
            c.start();
            d.start();
            e.start();
        }
    }

在这里插入图片描述

A和B是基本上同时运行的,产生了非线程安全问题

1.2.9 Servlet技术也会引起“非线程安全”问题

    package org.example.第一章Java多线程技能.N02使用多线程.N09Servlet技术也会引起非线程安全问题;

    public class LoginSerlvet {

        private static String usernameRef;
        private static String passwordRef;

        public static void doPost(String username,String password){
            try {
                usernameRef=username;
                if (usernameRef.equals("a")){
                    Thread.sleep(5000);
                }
                passwordRef = password;
                System.out.println("username=" + usernameRef + " password=" + password);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }

    package org.example.第一章Java多线程技能.N02使用多线程.N09Servlet技术也会引起非线程安全问题;

    public class ALogin  extends Thread{
        @Override
        public void run() {
            super.run();
            LoginSerlvet.doPost("a","aa");
        }
    }

    package org.example.第一章Java多线程技能.N02使用多线程.N09Servlet技术也会引起非线程安全问题;

    public class BLogin extends Thread{
        @Override
        public void run() {
            super.run();
            LoginSerlvet.doPost("b","bb");
        }
    }

    package org.example.第一章Java多线程技能.N02使用多线程.N09Servlet技术也会引起非线程安全问题;

    public class Run {
        public static void main(String[] args) {
            ALogin aLogin=new ALogin();
            aLogin.start();
            BLogin bLogin=new BLogin();
            bLogin.start();
        }
    }

在这里插入图片描述
在这里插入图片描述

解决相关问题使用synchronized关键字:
可以保证同一时间只有一个线程在执行方法
在这里插入图片描述

1.2.10 留意i–与System.out.println()出现的“非线程安全”问题

println()方法与i–联合使用时“有可能”出现的另外一种异常情况,并说明其产生的原因。

package org.example.第一章Java多线程技能.N02使用多线程.N10i递减和输出非线程安全问题;

public class MyThread extends Thread{
    private  int i=5;

    @Override
    public void run() {
        super.run();
        System.out.println("i=" + (i--) + "threadName="+Thread.currentThread().getName());
    }
}
package org.example.第一章Java多线程技能.N02使用多线程.N10i递减和输出非线程安全问题;

public class Run {
    public static void main(String[] args) {
        MyThread run=new MyThread();
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        Thread t3 = new Thread(run);
        Thread t4 = new Thread(run);
        Thread t5 = new Thread(run);

        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();

    }
}

在这里插入图片描述

虽然println()方法在内部是synchronized同步的,但i–操作却是在进入println()之前发生的,所以有一定概率发生非线程安全问题

1.2.11 方法run()被JVM所调用

当start()方法执行后,由JVM调用run()方法:

1.3 方法currentThread()

在这里插入图片描述

说明main方法是被名为main的线程调用的。
这里的main指的是名为main的线程

package org.example.第一章Java多线程技能.N03方法currentThread;

public class MyThread extends Thread{
    public MyThread(){
        System.out.println("构造方法的打印:" + Thread.currentThread().getName());
    }

    @Override
    public void run() {
        super.run();
        System.out.println("run方法的打印:" + Thread.currentThread().getName());
    }
}
package org.example.第一章Java多线程技能.N03方法currentThread;

public class Run2 {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        myThread.start();
    }
}

构造方法的打印:main
run方法的打印:Thread-0
MyThread.java类的构造方法是被main线程调用的,
而run方法是被名为Thread-0的线程调用的,run方法是被JVM自动调用的方法。

将Run2进行修改


package org.example.第一章Java多线程技能.N03方法currentThread;

public class Run2 {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
//        myThread.start();
        myThread.run();
    }
}

构造方法的打印:main
run方法的打印:main

start和run方法的区别:
1)my.run();:立即执行run()方法,不启动新的线程。
2)my.start();:执行run()方法时机不确定时,启动新的线程。

不要认为所有的构造方法都必须由main线程调用,要结合实际情况与写法确定,其他线程也可以调用构造方法,比如main方法启动A线程又在A线程中的run()方法里启动B线程

package org.example.第一章Java多线程技能.N03方法currentThread;

public class CountOperate extends Thread{
    public CountOperate() {
        System.out.println("CountOperate---begin");
        System.out.println("Thread.currentThread().getName()=" + Thread.currentThread().getName());
        System.out.println("this.getName()=" + this.getName());
        System.out.println("CountOperate---end");
    }
    
    @Override
    public void run() {
        super.run();
        System.out.println("run---begin");
        System.out.println("Thread.currentThread().getName()=" + Thread.currentThread().getName());
        System.out.println("this.getName()=" + this.getName());
        System.out.println("run---end");

    }
}
package org.example.第一章Java多线程技能.N03方法currentThread;

public class Run {
    public static void main(String[] args) {
        CountOperate countOperate=new CountOperate();
        Thread thread=new Thread(countOperate);
        thread.setName("A");
        thread.start();
    }
}

CountOperate---begin
Thread.currentThread().getName()=main
this.getName()=Thread-0
CountOperate---end
run---begin
Thread.currentThread().getName()=A
this.getName()=Thread-0
run---end

代码this.getName()代表CountOperate对象的name名称,由于CountOperate对象的name名称从未设置,所以默认为Thread-0。

1.4 方法isAlive()

isAlive()方法的功能是判断线程对象是否存活。

package org.example.第一章Java多线程技能.N04方法isAlive;

public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        System.out.println("run="+this.isAlive());
    }
}
package org.example.第一章Java多线程技能.N04方法isAlive;

public class Run {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        System.out.println("begin:"+myThread.isAlive());
        myThread.start();
        System.out.println("end:"+myThread.isAlive());
    }
}

在这里插入图片描述

end:虽然其输出的值是true,但此值是不确定的,输出true值是因为mythread线程还未执行完毕

package org.example.第一章Java多线程技能.N04方法isAlive;

public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread=new MyThread();
        System.out.println("begin:"+myThread.isAlive());
        myThread.start();
        Thread.sleep(1000);
        System.out.println("end:"+myThread.isAlive());
    }
}

在这里插入图片描述

end:输出的结果为false,因为mythread对象已经在1秒之内执行完毕。(main主线程执行的Thread.sleep(1000)方法会使main主线程停止1秒,而不是将mythread线程停止1秒)

package org.example.第一章Java多线程技能.N04方法isAlive;

public class CountOperate extends Thread{
    public CountOperate() {
        System.out.println("CountOperate---begin");
        System.out.println("Thread.currentThread().getName()=" + Thread.currentThread().getName());
        System.out.println("Thread.currentThread().isAlive()=" + Thread.currentThread().isAlive());
        System.out.println("this.getName()=" + this.getName());
        System.out.println("this.isAlive()=" + this.isAlive());
        System.out.println("CountOperate---end");
    }

    @Override
    public void run() {
        System.out.println("run---begin");
        System.out.println("Thread.currentThread().getName()=" + Thread.currentThread().getName());
        System.out.println("Thread.currentThread().isAlive()=" + Thread.currentThread().isAlive());
        System.out.println("this.getName()=" + this.getName());
        System.out.println("this.isAlive()=" + this.isAlive());
        System.out.println("run---end");
    }

}
package org.example.第一章Java多线程技能.N04方法isAlive;

public class Run1 {
    public static void main(String[] args) {
        CountOperate countOperate=new CountOperate();
        Thread thread = new Thread(countOperate);
        System.out.println("main begin t1 isAlive=" + thread.isAlive());
        thread.setName("A");
        thread.start();
        System.out.println("main end t1 isAlive=" + thread.isAlive());
    }
}

在这里插入图片描述

在使用isAlive()方法时,如果将线程对象以构造参数的方式传递给Thread对象进行start()启动,则运行的结果和前面的示例是有差异的,造成这样的差异的原因是Thread.currentThread()和this的差异,

关于Thread.currentThread().getName() 和 this.getName()区别详解

currentThread的详解

currentThread方法是Thread类的一个静态方法,用来获取当前运行的代码段,正在被哪个线程调用。我们先来看一眼源码。
在这里插入图片描述

public static void main(String[] args) {
        String name = Thread.currentThread().getName();
        System.out.println(name);
    }

输出的结果为main。

为什么为main呢

java的项目在启动的时候,会创立一个进程,这个进程同样也是一个线程,在java里面他就叫做main线程。他的名字在设定的时候就是main。我们可以看到上面的代码就是在main方法下执行的,也就是由main线程来执行,所以我们打印出来的名字是main。

创建一个新的线程

public class TestThread extends Thread {

    public TestThread() {
        System.out.println("构造方法:" + Thread.currentThread().getName());
    }

    @Override
    public void run() {
        System.out.println("run方法:" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        TestThread testThread = new TestThread();
        testThread.start();
    }

}
构造方法:main
run方法:Thread-0

这里我们只是声明了一个线程对象类,这个新的线程没有创建也没有启动,我们仅仅把它理解为一个普通对象即可。那么由于是在main方法里面,那么执行他的一定是main线程,所以可以看到构造方法输出的结果是main。
再来看start方法里面,为什么变成了thread-0了呢。
我们知道java的多线程创建的一种方式就是继承thread类。然后实现里面的run方法。这样当线程start的时候,就会调用内部的start0的本地方法,实际就是会执行run的实现方法。当run方法执行的时候,一定是由我们创建的线程去执行的,而不是main线程,所以我们就可以得知打印出来的是新线程的名字thread0。
更多见

1.5 方法sleep(long millis)

sleep()方法的作用是在指定的毫秒数内让当前“正在执行的线程”休眠(暂停执行),这个“正在执行的线程”是指this.currentThread()返回的线程。

package org.example.第一章Java多线程技能.N05方法sleep;

public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        try {
            System.out.println("run threadName=" + this.currentThread().getName() + " begin "+System.currentTimeMillis());
            Thread.sleep(2000);
            System.out.println("run threadName=" + this.currentThread().getName() + " end "+System.currentTimeMillis());

        }catch (InterruptedException e){

        }
    }
}
package org.example.第一章Java多线程技能.N05方法sleep;

public class Run {
    public static void main(String[] args) {
        MyThread mythread = new MyThread();
        System.out.println("begin =" + System.currentTimeMillis());
        mythread.start();
        System.out.println("end   =" + System.currentTimeMillis());
    }
}

在这里插入图片描述

由于main线程与MyThread2线程是异步执行的,所以首先输出的信息为begin和end,而MyThread2线程是后运行的

1.6 方法sleep(long millis, int nanos)

public static void sleep(long millis, intnanos)方法的作用是让当前正在执行的线程在指定的毫秒数加指定的纳秒数内休眠(暂停执行),此操作受到系统计时器及调度程序精度及准确性的影响

1.7 方法StackTraceElement[] getStackTrace()

作用:返回一个表示该线程的堆栈跟踪元素数组。如果该线程尚未启动或已经终止,则该方法将返回一个零长度数组。如果返回的数组不是零长度的,则其第一个元素代表堆栈顶,它是该数组中最新的方法调用。最后一个元素代表堆栈底,是该数组中最旧的方法调用。

package org.example.第一章Java多线程技能.方法StackTraceElementgetStackYrace;

public class Test1 {
    public void a() {
        b();
    }
    public void b() {
        c();
    }

    public void c() {
        d();
    }

    public void d() {
        e();
    }

    public void e(){
        StackTraceElement[] stackTraceElements=Thread.currentThread().getStackTrace();
        if (stackTraceElements!=null){
            for (int i=0;i<stackTraceElements.length;i++){
                StackTraceElement stackTraceElement=stackTraceElements[i];
                System.out.println("className="+stackTraceElement.getClassName()+" methodName="
                        + stackTraceElement.getMethodName() +
                        " fileName=" + stackTraceElement.getFileName() +
                        " lineNumber=" + stackTraceElement.getLineNumber());
                //StackTraceElement.getLineNumber()方法返回一个的源代码行的行号包含由该堆栈跟踪元素所表示的执行点。
            }
        }
    }

    public static void main(String[] args) {
        Test1 test1=new Test1();
        test1.a();
    }

}

在这里插入图片描述

1.8 方法static void dumpStack()

作用是将当前线程的堆栈信息输出至标准错误流。该方法仅用于调试。

package org.example.第一章Java多线程技能.N08方法staticvoiddumpStack;

public class Test {
    public void a() {
        b();
    }

    public void b() {
        c();
    }

    public void c() {
        d();
    }

    public void d() {
        e();
    }
    public void e() {
        int age = 0;
        age = 100;
        if (age == 100) {
            Thread.dumpStack();
        }
    }

    public static void main(String[] args) {
        Test test = new Test();
        test.a();
    }

}

在这里插入图片描述

1.9 方法Map<Thread, StackTraceElement[]> getAllStackTraces()

作用是返回所有活动线程的堆栈信息的一个映射。
Map的key是线程对象,
而Map的value是一个StackTraceElement数组,该数组表示相应Thread的堆栈信息
在调用该方法的同时,线程可能也在执行。每个线程的堆栈信息仅代表线程当时状态的一个快照

package org.example.第一章Java多线程技能.N09方法Map;

import java.util.Iterator;
import java.util.Map;

public class Test1 {
    public void a() {
        b();
    }

    public void b() {
        c();
    }

    public void c() {
        d();
    }

    public void d() {
        e();
    }

    public void e(){
        Map<Thread,StackTraceElement[]> map=Thread.currentThread().getAllStackTraces();
        if (map!=null && map.size()!=0) {
            Iterator keyIterator = map.keySet().iterator();
            while (keyIterator.hasNext()) {
                Thread eachThread = (Thread) keyIterator.next();
                StackTraceElement[] array = map.get(eachThread);
                System.out.println("------每个线程的基本信息");
                System.out.println("  线程名称:" + eachThread.getName());
                System.out.println(" StackTraceElement[].length=" + array.length);
                System.out.println("线程状态:" + eachThread.getState());
                if (array.length != 0) {
                    System.out.println("  打印StackTraceElement[]数组具体信息:");
                    for (int i = 0; i < array.length; i++) {
                        StackTraceElement eachElement = array[i];
                        System.out.println("    " + eachElement.getClassName() +
                                " " + eachElement.getMethodName() +
                                " " + eachElement.getFileName() +
                                " " + eachElement.getLineNumber());
                    }
                } else {
                    System.out.println("  没有StackTraceElement[]信息,因为线程" + eachThread.getName() + "中的StackTraceElement[].length==0");
                }
                System.out.println();
                System.out.println();
            }
        }
    }

    public static void main(String[] args) {
        Test1 test1=new Test1();
        test1.a();
    }
}
------每个线程的基本信息
  线程名称:Monitor Ctrl-Break
 StackTraceElement[].length=4
线程状态:RUNNABLE
  打印StackTraceElement[]数组具体信息:
    java.net.InetAddress <clinit> InetAddress.java 347
    java.net.InetSocketAddress <init> InetSocketAddress.java 229
    java.net.Socket <init> Socket.java 287
    com.intellij.rt.execution.application.AppMainV2$1 run AppMainV2.java 51


------每个线程的基本信息
  线程名称:Common-Cleaner
 StackTraceElement[].length=5
线程状态:TIMED_WAITING
  打印StackTraceElement[]数组具体信息:
    java.lang.Object wait Object.java -2
    java.lang.ref.ReferenceQueue remove ReferenceQueue.java 155
    jdk.internal.ref.CleanerImpl run CleanerImpl.java 140
    java.lang.Thread run Thread.java 833
    jdk.internal.misc.InnocuousThread run InnocuousThread.java 162


------每个线程的基本信息
  线程名称:Signal Dispatcher
 StackTraceElement[].length=0
线程状态:RUNNABLE
  没有StackTraceElement[]信息,因为线程Signal Dispatcher中的StackTraceElement[].length==0


------每个线程的基本信息
  线程名称:Finalizer
 StackTraceElement[].length=4
线程状态:WAITING
  打印StackTraceElement[]数组具体信息:
    java.lang.Object wait Object.java -2
    java.lang.ref.ReferenceQueue remove ReferenceQueue.java 155
    java.lang.ref.ReferenceQueue remove ReferenceQueue.java 176
    java.lang.ref.Finalizer$FinalizerThread run Finalizer.java 183


------每个线程的基本信息
  线程名称:Attach Listener
 StackTraceElement[].length=0
线程状态:RUNNABLE
  没有StackTraceElement[]信息,因为线程Attach Listener中的StackTraceElement[].length==0


------每个线程的基本信息
  线程名称:Notification Thread
 StackTraceElement[].length=0
线程状态:RUNNABLE
  没有StackTraceElement[]信息,因为线程Notification Thread中的StackTraceElement[].length==0


------每个线程的基本信息
  线程名称:main
 StackTraceElement[].length=8
线程状态:RUNNABLE
  打印StackTraceElement[]数组具体信息:
    java.lang.Thread dumpThreads Thread.java -2
    java.lang.Thread getAllStackTraces Thread.java 1662
    org.example.第一章Java多线程技能.N09方法Map.Test1 e Test1.java 24
    org.example.第一章Java多线程技能.N09方法Map.Test1 d Test1.java 20
    org.example.第一章Java多线程技能.N09方法Map.Test1 c Test1.java 16
    org.example.第一章Java多线程技能.N09方法Map.Test1 b Test1.java 12
    org.example.第一章Java多线程技能.N09方法Map.Test1 a Test1.java 8
    org.example.第一章Java多线程技能.N09方法Map.Test1 main Test1.java 55


------每个线程的基本信息
  线程名称:Reference Handler
 StackTraceElement[].length=3
线程状态:RUNNABLE
  打印StackTraceElement[]数组具体信息:
    java.lang.ref.Reference waitForReferencePendingList Reference.java -2
    java.lang.ref.Reference processPendingReferences Reference.java 253
    java.lang.ref.Reference$ReferenceHandler run Reference.java 215



进程已结束,退出代码0

1.10 方法getId()

getId()方法可以取得线程的唯一数字标识。

package org.example.第一章Java多线程技能.N10方法getId;

public class Test1 {
    public static void main(String[] args) {
        Thread runThread = Thread.currentThread();
        System.out.println(runThread.getName() + " " + runThread.getId());
        Thread t1 = new Thread();
        System.out.println(t1.getName() + " " + t1.getId());
        Thread t2 = new Thread();
        System.out.println(t2.getName() + " " + t2.getId());
        Thread t3 = new Thread();
        System.out.println(t3.getName() + " " + t3.getId());
        Thread t4 = new Thread();
        System.out.println(t4.getName() + " " + t4.getId());
        Thread t5 = new Thread();
        System.out.println(t5.getName() + " " + t5.getId());
    }
}
main 1
Thread-0 24
Thread-1 25
Thread-2 26
Thread-3 27
Thread-4 28

从运行结果来看,当前执行代码的线程名为main,线程id值为1。
而Thread-0线程的id值直接到达24,说明中间有23个id值被隐藏的线程占有

11.1 停止线程

停止一个线程意味着在线程处理完任务之前停掉正在做的操作,也就是放弃当前操作。
虽然停止一个线程可以用stop方法但是并不推荐使用
大多数情况还是使用interrupt方法停止一个线程,但此方法不会停止衣蛾正在运行的线程,需要加入一个判断才可以完线程的停止

java线程停止的三种方法:

  • 使用退出标志是线程正常退出
  • stop强行停止,和suspend,resume一样,都是过期作废的方法
  • 使用interrupt中断线程

11.1.1 停止不了的线程

interrupt方法的使用效果不像for+break那样马上停止循环,只是在线程中打上一个停止的标志。

11.1.2 判断是不是停止状态

  1. public static boolean interrupted():测试currentThread是否已经中断,有清除状态的作用(连续两次调用,第二次返回false)
  2. public boolean this.isInterrupted():测试this关键字所在线程类的对象是否已经中断

1.11.3 清除中断状态的使用场景

package org.example.第一章Java多线程技能.N10方法getId.N03清除中断状态;

import java.lang.reflect.Array;
import java.util.ArrayList;

public class Box {
    public static ArrayList list1=new ArrayList();
    public static ArrayList list2=new ArrayList();
}
package org.example.第一章Java多线程技能.N10方法getId.N03清除中断状态;

public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        try {
            while (true) {
                if (this.isInterrupted()) {
                    throw new InterruptedException("1 线程被中断了");
                    //模拟执行任务的耗时,不能用sleep,遇到interrupt方法会产生异常
                }

                for (int i = 0; i < 10000; i++) {
                    new String("" + Math.random());
                }

                Box.list1.add("生产数据A");
                System.out.println("list1 size=" + Box.list1.size());
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }

        try {
            while (true){
                if (this.isInterrupted()){
                    throw new InterruptedException("2线程被中断");
                }

                for (int i=0;i<10000;i++){
                    new String(""+Math.random());
                }

                Box.list2.add("生产数据B");
                System.out.println("list2 size="+Box.list2.size());
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
package org.example.第一章Java多线程技能.N10方法getId.N03清除中断状态;

public class Text1 {
    public static void main(String[] args) throws InterruptedException{
        MyThread myThread=new MyThread();
        myThread.start();;
        boolean list1Isinterrupted=false;
        boolean list2Isinterrupted=false;
        while (myThread.isAlive()){
            if (Box.list1.size()>=500 && list1Isinterrupted==false){
                myThread.interrupt();
                list1Isinterrupted=true;
            }
            if (Box.list2.size()>=600 && list2Isinterrupted==false){
                myThread.interrupt();
                list2Isinterrupted=true;
            }
            Thread.sleep(50);
        }
    }
}

在这里插入图片描述

使用了isInterrupt()方法作为判断条件,方法不会清除中断状态返回值一直是true

当使用interupted()时,两个list都添加上了数据,清除了中断状态,进程被销毁,程序没出现问题
在这里插入图片描述
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nqWOVk66-1672621194330)(https://note.youdao.com/yws/res/2012/WEBRESOURCE46f8ba06488a8e0b815b14d3c888684e)]

1.11.4 能停止的线程——异常法

package org.example.第一章Java多线程技能.N11停止线程.N04异常法;

public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        for (int i=0;i<600000;i++){
            if (this.interrupted()){
                System.out.println("已经是停止状态了,我要退出了" );
                break;
            }
            System.out.println("i="+i);
        }
        System.out.println("被输出,for语句之后又继续运行,线程未停止");
    }
}
package org.example.第一章Java多线程技能.N11停止线程.N04异常法;

public class Run {
    public static void main(String[] args) {
        try {
            MyThread myThread=new MyThread();
            myThread.start();
            Thread.sleep(1000);
            myThread.interrupt();
        }catch (InterruptedException e){
            System.out.println("main catch");
            e.printStackTrace();
        }
        System.out.println("end");
    }
}

在这里插入图片描述

package org.example.第一章Java多线程技能.N11停止线程.N04异常法;

public class MyThread2 extends Thread{
    @Override
    public void run() {
        try {
            super.run();
            for (int i=0;i<600000;i++){
                if (this.interrupted()){
                    System.out.println("已经是停止状态了,我要退出了" );
//                break;
                    throw new InterruptedException();
                }
                System.out.println("i="+i);
            }
            System.out.println("我在for下面");
        }catch (InterruptedException e){
            System.out.println("进入MyThread中的catch");
            e.printStackTrace();
        }

    }
}
package org.example.第一章Java多线程技能.N11停止线程.N04异常法;

public class Run2 {
    public static void main(String[] args) {
        try {
            MyThread2 myThread=new MyThread2();
            myThread.start();
            Thread.sleep(1000);
            myThread.interrupt();
        }catch (InterruptedException e){
            System.out.println("main catch");
            e.printStackTrace();
        }
        System.out.println("end");
    }
}

for语句后面的输出语句没有输出

1.11.5 在sleep状态下停止

package org.example.第一章Java多线程技能.N11停止线程.N05在sleep状态下停止;

public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        try {
            System.out.println("run begin");
            Thread.sleep(200000);
            System.out.println("ren end");
        }catch (Exception e){
            System.out.println("在sleep下 被停止,进入catch"+this.isInterrupted());
            e.printStackTrace();
        }
    }
}
package org.example.第一章Java多线程技能.N11停止线程.N05在sleep状态下停止;

public class Run {
    public static void main(String[] args) {
        try {
            MyThread myThread=new MyThread();
            myThread.start();
            Thread.sleep(200);
            myThread.interrupt();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("end");
    }
}

在这里插入图片描述

不管调用顺序,只要interrupt()sleep()方法同时出现就会产生异常
1)sleep下运行interrupt方法会产生异常
2)interrupt给线程打了中断标记,再执行sleep会出现异常

1.11.6 使用stop()暴力停止线程

package org.example.第一章Java多线程技能.N11停止线程.N06暴力停止stop;

public class MyThread extends Thread{
    private int i=0;

    @Override
    public void run() {
        super.run();
        try {
            while (true){
                i++;
                System.out.println("i="+i);
                Thread.sleep(1000);
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
package org.example.第一章Java多线程技能.N11停止线程.N06暴力停止stop;

public class Run {
    public static void main(String[] args) {
        try {
            MyThread myThread=new MyThread();
            myThread.start();
            Thread.sleep(8000);
            myThread.stop();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

stop方法呈删除线状态,,是过期作废的方法,
stop方法容易造成业务处理的不确定性(不能确定在哪里停止)

1.11.7 方法stop()与java.lang.ThreadDeath

package org.example.第一章Java多线程技能.N11停止线程.N07ThreadDeath;

public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        try {
//            Thread.sleep(2000);
//            int i=100;
//            System.out.println("begin");
//            if (i==100){
//                this.stop();
//            }
//            System.out.println("end");
            this.stop();;
        }catch (ThreadDeath e){
            System.out.println("进入catch");
            e.printStackTrace();
        }
    }
}
package org.example.第一章Java多线程技能.N11停止线程.N07ThreadDeath;

public class Run {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        myThread.start();
    }
}

在这里插入图片描述

package org.example.第一章Java多线程技能.N11停止线程.N07ThreadDeath;

public class MyThread2 extends Thread{
    @Override
    public void run() {
        super.run();
        try {
            for (int i=1;i<500000;i++){
                System.out.println("i="+i);
            }
        }catch (ThreadDeath e){
            System.out.println("进入MyThread2下面的catch");
            e.printStackTrace();
        }
    }
}
package org.example.第一章Java多线程技能.N11停止线程.N07ThreadDeath;

public class Run2 {
    public static void main(String[] args) {
        try {
            MyThread2 myThread=new MyThread2();
            myThread.start();
            Thread.sleep(100);
            myThread.stop();
        }catch (InterruptedException e){
            System.out.println("Run2下的InterruptedException");
            e.printStackTrace();
        }
        catch (ThreadDeath e){
            System.out.println("Run2下的ThreadDeath");
            e.printStackTrace();
        }


    }
}

在这里插入图片描述

外界对线程对象调用stop方法时,线程内部抛出ThreadDeath异常
外界不会抛出ThreadDeath异常

1.11.8 使用stop()释放锁导致数据结果不一致

package org.example.第一章Java多线程技能.N11停止线程.N08stop释放锁导致数据结果不一致;

public class MyService {
    private String username="a";
    private String password="aa";

    synchronized public String getUsername(){
        return username;
    }

    synchronized public String getPassword(){
        return password;
    }

    synchronized public void printString(String username,String password){
        try {
            this.username=username;
            Thread.sleep(1000000);
            this.password=password;
        }catch (InterruptedException e){
         e.printStackTrace();
        }
    }
}
package org.example.第一章Java多线程技能.N11停止线程.N08stop释放锁导致数据结果不一致;

public class MyThreadA extends Thread{
    public MyService myService;

    public MyThreadA(MyService myService) {
        super();
        this.myService = myService;
    }

    @Override
    public void run() {
        super.run();
        myService.printString("b","bb");
    }
}
package org.example.第一章Java多线程技能.N11停止线程.N08stop释放锁导致数据结果不一致;

public class MyThreadB extends Thread{
    public MyService myService;

    public MyThreadB(MyService myService) {
        super();
        this.myService = myService;
    }

    @Override
    public void run() {
        super.run();
        System.out.println(myService.getUsername()+" "+myService.getPassword());
        System.out.println("end"+System.currentTimeMillis());
    }
}
package org.example.第一章Java多线程技能.N11停止线程.N08stop释放锁导致数据结果不一致;

public class Run {
    public static void main(String[] args) throws InterruptedException{
        MyService myService=new MyService();
        MyThreadA myThreadA=new MyThreadA(myService);
        MyThreadB myThreadB=new MyThreadB(myService);
        myThreadA.start();
        Thread.sleep(500);
        myThreadB.start();
        System.out.println("begin"+System.currentTimeMillis());
        Thread.sleep(500);
        myThreadA.stop();
    }
}

在这里插入图片描述

当执行stop方法时才会释放锁,线程b才能同步get方法
并且synchronized同步的方法取出的是未处理完的半成品方法

1.11.9 使用return;语句停止线程的缺点及相应解决方案

package org.example.第一章Java多线程技能.N11停止线程.N09使用return停止线程;

public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        while (true){
            if (this.isInterrupted()){
                System.out.println("停止了");
                return;
            }
            System.out.println("time:"+System.currentTimeMillis());
        }
    }
}
package org.example.第一章Java多线程技能.N11停止线程.N09使用return停止线程;

public class Run {
    public static void main(String[] args) throws InterruptedException{
        MyThread myThread=new MyThread();
        myThread.start();
        Thread.sleep(2000);
        myThread.interrupt();
    }
}

在这里插入图片描述

相比于抛异常法,在代码结构上可以更方便的停止线程,不过还是建议使用抛异常法,该方法可以在catch块对异常信息进行统一处理

return

package org.example.第一章Java多线程技能.N11停止线程.N09使用return停止线程;

public class MyThread1 extends Thread{
    @Override
    public void run() {
        super.run();
        //insert
        if (this.interrupted()){
            System.out.println("写入log info");
            return;
        }
        //insert
        if (this.interrupted()){
            System.out.println("写入log info");
            return;
        }
        //insert
        if (this.interrupted()){
            System.out.println("写入log info");
            return;
        }
        //insert
        if (this.interrupted()){
            System.out.println("写入log info");
            return;
        }
        System.out.println("for for for for");
    }
}

catch

package org.example.第一章Java多线程技能.N11停止线程.N09使用return停止线程;

public class MyThread2 extends Thread{
    @Override
    public void run() {
        try {
            super.run();
            //insert
            if (this.interrupted()){
                throw new InterruptedException();
            }
            //insert
            if (this.interrupted()){
                throw new InterruptedException();
            }
            //insert
            if (this.interrupted()){
                throw new InterruptedException();
            }
            //insert
            if (this.interrupted()){
                throw new InterruptedException();
            }
        }catch (InterruptedException e){
            System.out.println("写入log info");
            e.printStackTrace();
        }

    }
}

catch可以进行集中处理

1.12 暂停线程

暂停线程意味着线程暂停后还能继续运行

suspend:暂停线程
resume():恢复线程

package org.example.第一章Java多线程技能.N12暂停线程.N01suspend和resume;

public class MyThread extends Thread{
    private long i=0;

    public long getI() {
        return i;
    }

    @Override
    public void run() {
        super.run();
        while (true){
            i++;
        }
    }
}
package org.example.第一章Java多线程技能.N12暂停线程.N01suspend和resume;

import java.util.Map;

public class Run {
    public static void main(String[] args) {
        try {
            MyThread myThread=new MyThread();
            myThread.start();
            Thread.sleep(5000);
            myThread.suspend();
            System.out.println("A="+System.currentTimeMillis()+" i="+myThread.getI());
            Thread.sleep(5000);
            System.out.println("A="+System.currentTimeMillis()+" i="+myThread.getI());

            myThread.resume();
            Thread.sleep(5000);

            myThread.suspend();
            System.out.println("B="+System.currentTimeMillis()+" i="+myThread.getI());
            Thread.sleep(5000);
            System.out.println("B="+System.currentTimeMillis()+" i="+myThread.getI());
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

stop()方法用于销毁线程对象如果想要继续运行线程,则必须用start()重新启用线程
suspend()方法用于让线程不再执行任务,但线程对象不被销毁,未来还可以恢复运行

1.12.2 suspend()与resume()方法的缺点:独占

情况1:

package org.example.第一章Java多线程技能.N12暂停线程.N02独占;

public class SynchronizedObject {
    synchronized public void printString(){
        System.out.println("begin");
        if (Thread.currentThread().getName().equals("a")){
            System.out.println("a线程永远suspend了");
            Thread.currentThread().suspend();
        }
        System.out.println("end");
    }
}
package org.example.第一章Java多线程技能.N12暂停线程.N02独占;

public class Run {
    public static void main(String[] args) {
        try {
            final SynchronizedObject object=new SynchronizedObject();
            Thread thread1=new Thread(){
                @Override
                public void run() {
                    super.run();
                    object.printString();
                }
            };

            thread1.setName("a");
            thread1.start();

            Thread.sleep(1000);

            Thread thread2=new Thread(){
                @Override
                public void run() {
                    super.run();
                    System.out.println("thread2启动了。但进入不了printString,只打印一个begin");
                    System.out.println("printString被a线程锁定并永远的暂停了");
                    object.printString();
                }
            };
            thread2.start();
        }catch (InterruptedException e){
            e.printStackTrace();
        }


    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qC9zqHgr-1672621194334)(https://note.youdao.com/yws/res/2129/WEBRESOURCE445da76f834cf70a9d3fc597feb7dc2d)]

package org.example.第一章Java多线程技能.N12暂停线程.N02独占;

import java.util.Map;

public class MyThread extends Thread {
    private long i=0;

    @Override
    public void run() {
        super.run();
        while (true){
            i++;
        }
    }
}
package org.example.第一章Java多线程技能.N12暂停线程.N02独占;

public class Run2 {
    public static void main(String[] args) {
        try {
            MyThread myThread=new MyThread();
            myThread.start();;
            Thread.sleep(1000);
            System.out.println("main end");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

main进程虽然被销毁了,但myThread还在运行

package org.example.第一章Java多线程技能.N12暂停线程.N02独占;

import java.util.Map;

public class MyThread extends Thread {
    private long i=0;

    @Override
    public void run() {
        super.run();
        while (true){
            i++;
            System.out.println(i);
        }
    }
}

在这里插入图片描述
在这里插入图片描述

当 System.out.println ()方法被暂停时,同步锁时不释放的
main线程未销毁,当因为锁未销毁,不能输出main end

1.12.3 suspend()与resume()方法的缺点:数据不完整

package org.example.第一章Java多线程技能.N12暂停线程.N03数据不完整;

public class MyObject {
    private String username="1";
    private String password="11";

    public void setValue(String u,String p){
        this.username=u;
        if (Thread.currentThread().getName().equals("a")){
            System.out.println("停止a线程");
            Thread.currentThread().suspend();
        }
        this.password=p;
    }

    public void printup(){
        System.out.println(username+" "+password);
    }
}
package org.example.第一章Java多线程技能.N12暂停线程.N03数据不完整;

public class Run {

    public static void main(String[] args) throws InterruptedException{
        final MyObject myObject=new MyObject();

        Thread thread1=new Thread(){
            @Override
            public void run() {
                super.run();
                myObject.setValue("a","aa");
                System.out.println("123");
            }
        };

        thread1.setName("a");
        thread1.start();

        Thread.sleep(500);

        Thread thread2=new Thread(){
            @Override
            public void run() {
                super.run();
                myObject.printup();
            }
        };
        thread2.start();
    }
}

在这里插入图片描述

1.12.4 使用LockSupport类实现线程的暂停恢复

package org.example.第一章Java多线程技能.N12暂停线程.ThreadSupport;

import java.util.concurrent.locks.LockSupport;

public class MyThreaad1 extends Thread{
    @Override
    public void run() {
        super.run();
        System.out.println("begin"+System.currentTimeMillis());
        LockSupport.park();
        System.out.println("end"+System.currentTimeMillis());
    }
}
package org.example.第一章Java多线程技能.N12暂停线程.ThreadSupport;

import java.util.concurrent.locks.LockSupport;

public class Run {
    public static void main(String[] args) throws InterruptedException{
        MyThreaad1 myThreaad1=new MyThreaad1();
        myThreaad1.start();;
        Thread.sleep(2000);
        LockSupport.unpark(myThreaad1);
    }
}

park:线程暂停
unprk:恢复线程运行

1.13 方法yield()

yield() 作用是放弃当前CPU资源,让其他任务去占用CPU的执行时间,放弃时间不确定,有可能刚刚放弃,马上又获得CPU时间片

package org.example.第一章Java多线程技能.N13yield;

public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        long begin=System.currentTimeMillis();
        int count=0;
        for (int i=0;i<50000000;i++){
           // Thread.yield();
            count=count+(i+1);
        }
        long end=System.currentTimeMillis();
        System.out.println("用时"+(end-begin));
    }
}
package org.example.第一章Java多线程技能.N13yield;

public class Run {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        myThread.start();
    }
}

1.14 线程的优先级

在操作系统中,优先级较高的线程得到的CPU资源较多,CPU优先执行优先级较高的线程对象中的任务(让优先级较高的线程获得更多的CPU时间片)

1.14.1 线程优先级的继承特性

A线程启动B线程,A、B线程优先级一样

package org.example.第一章Java多线程技能.N14优先级.N01继承特性;

public class MyThread1 extends Thread{
    @Override
    public void run() {
        super.run();
        System.out.println("A:"+this.getPriority());
        MyThread2 myThread2=new MyThread2();
        myThread2.start();
    }
}
package org.example.第一章Java多线程技能.N14优先级.N01继承特性;

public class MyThread2 extends Thread{
    @Override
    public void run() {
        super.run();
        System.out.println("B"+this.getPriority());
    }
}
package org.example.第一章Java多线程技能.N14优先级.N01继承特性;

public class Run {
    public static void main(String[] aSSrgs) {
        System.out.println("main begin:"+Thread.currentThread().getPriority());
//        Thread.currentThread().setPriority(7);
        System.out.println("main end"+Thread.currentThread().getPriority());
        MyThread1 myThread1=new MyThread1();
        myThread1.start();
    }
}

在这里插入图片描述

1.14.2 线程优先级的规律性

package org.example.第一章Java多线程技能.N14优先级.N02规律性;

import java.util.Random;

public class MyThread1 extends Thread{
    @Override
    public void run() {
        super.run();
        Long beginTime=System.currentTimeMillis();
        Long addResult= Long.valueOf(0);
        for (int i=0;i<50000;i++){
            Random random=new Random();
            random.nextInt();
            addResult=addResult+i;
        }
        long endTime=System.currentTimeMillis();
        System.out.println("Thread1:"+(endTime-beginTime));
    }
}
package org.example.第一章Java多线程技能.N14优先级.N02规律性;

import java.util.Random;

public class MyThread2 extends Thread{
    @Override
    public void run() {
        super.run();
        Long beginTime=System.currentTimeMillis();
        Long addResult= Long.valueOf(0);
            for (int i = 0; i < 50000; i++) {
                Random random = new Random();
                random.nextInt();
                addResult = addResult + i;
            }
        long endTime=System.currentTimeMillis();
        System.out.println("Thread2:"+(endTime-beginTime));
    }
}
package org.example.第一章Java多线程技能.N14优先级.N02规律性;

public class Run {
    public static void main(String[] args) {
        for (int i=1;i<10;i++){
            MyThread1 myThread1=new MyThread1();
            myThread1.setPriority(1);


            MyThread2 myThread2=new MyThread2();
            myThread2.setPriority(10);
            myThread1.start();
            myThread2.start();

        }
    }
}
Thread2:63
Thread2:44
Thread2:66
Thread2:62
Thread2:64
Thread2:47
Thread2:58
Thread1:67
Thread1:64
Thread2:71
Thread1:68
Thread1:65
Thread2:76
Thread1:36
Thread1:83
Thread1:37
Thread1:38
Thread1:86

1.14.3 线程优先级的随机性

不要把优先级和运行结果的顺序衡量
虽然线程的优先级较高的先执行,但不一定是先执行完。

1.15 守护线程

java有两种线程,一种是用户线程,也称非守护线程,另一种是守护线程

什么是守护线程
进程中不存在守护线程时,则守护线程自动销毁。典型的守护线程就是垃圾回收线程,当进程中没有非守护线程,则垃圾回收线程也就没有存在的必要了,自动销毁
守护Daemon线程的作用是为其他线程的运行提供便利的服务,最典型的GC(垃圾回收器)。
最后一个用户线程销毁了,进程也随之结束了

1.16 并发与并行

并发:一个CPU同时执行多个任务
并行:多个CPU或多核CPU同时执行多个任务

A同学一边打游戏,一边写作业,一边吃饭就是并发
A同学让B同学帮她发游戏,让C同学帮她写作业,自己吃饭就是并行

1.17 同步和异步

同步:需要等待处理的结果才能运行
异步:不需要等待处理的结果还能运行

1.18 多核CPU不一定比单核CPU运行的快

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/134707.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

hcip第五天实验

拓扑图 每台路由器都有两个环回&#xff0c;一个24的环回&#xff0c;一个32的环回&#xff1b;32的环回用于建邻&#xff0c;24的环回用于用户网段&#xff0c;最终所有24的环回可以ping通。 实验步骤 1.配置ip 2.让2,3,4号设备的IGP协议可以通信 3.两两之间建立BGP邻居关…

DR_CAN基尔霍夫电路题解法【自留用】

无目录如图所示电路&#xff0c;输入端电压eie_iei​&#xff0c;输出端电压eoe_oeo​&#xff0c;求二者之间关系。 对其中元件进行标号&#xff0c;并将电流环路标号&#xff0c;指出各元件的压降方向&#xff1a; v值得注意的是&#xff1a; 1&#xff09;电阻R2R_2R2​同时…

rabbitmq消息发送的可靠性:结合mysql来保证消息投递的可靠性

消息从生产者到Broker&#xff0c;则会触发confirmCallBack回调消息从exchange到Queue&#xff0c;投递失败则会调用returnCallBack 用一张表来记录发送到mq的每一条消息&#xff0c;方便发送失败需要重试。status&#xff1a; 1-正常&#xff0c;0-重试&#xff0c;2-失败。发…

【计算机视觉】OpenCV 4高级编程与项目实战(Python版)【1】:图像处理基础

目录 1. OpenCV简介 2. OpenCV开发环境搭建 3. 读取图像 4. 读取png文件出现警告 5. 显示图像 6. 保存图像 7. 获取图像属性 本系列文章会深入讲解OpenCV 4&#xff08;Python版&#xff09;的核心技术&#xff0c;并提供了大量的实战案例。这是本系列文章的第一篇&…

简单了解计算机的工作原理

文章目录一.计算机操作系统二.进程/任务三、进程控制块抽象(PCB)四、进程调度相关属性五、内存管理一.计算机操作系统 概念:操作系统是一组做计算机资源管理的软件的统称. 目前常见的操作系统有&#xff1a;Windows系列、Unix系列、Linux系列、OSX系列、Android系列、iOS系列…

百度安全在线查询,网站弹出风险提示怎么处理

站长们要避免网站打开弹出风险提示&#xff0c;需要要时刻关注自己的网站是否存在风险&#xff0c;时刻知道自己的网站是不是安全的。 百度安全在线查询步骤&#xff1a; 1、打开站长工具 2、添加需要查询的网站域名。 3、勾选百度安全。 4、点击开始查询。 等…

22个Python的万用公式分享

在大家的日常python程序的编写过程中&#xff0c;都会有自己解决某个问题的解决办法&#xff0c;或者是在程序的调试过程中&#xff0c;用来帮助调试的程序公式。小编通过几十万行代码的总结处理&#xff0c;总结出了22个python万用公式&#xff0c;可以帮助大家解决在日常的py…

再学C语言22:循环控制语句——循环嵌套和数组处理

嵌套循环&#xff08;nested loop&#xff09;&#xff1a;在一个循环内使用另一个循环 一、循环嵌套 示例代码&#xff1a; #include <stdio.h> int main(void) {int i;int j;for(i 0; i < 10; i){for(j 0; j < 9; j){printf("%5d", j); // 里面的…

共享模型之管程(二)

1.Moniter对象 1.1.Java对象头 1>.以32位虚拟机为例 ①.普通对象 Klass Word表示对象的类型,它是一个指针,指向了对象所从属的class; ②.数组对象 在32位虚拟机中,integer包装类型的长度为12个字节,而int基本数据类型的长度为4个字节; 其中Mark Word结构为: 2>.64位…

shell第一天练习

题目&#xff1a; 1、在当前主机编写脚本文件history_max.sh显示主机中执行频率最高的前5个命令。 2、判断主机是否存在rhel用户&#xff0c;如果存在则设置密码为redhat,如果不存在则创建用户并设置密码。 3、通过设置变量HISTTIMEFORMAT&#xff0c;使得当执行history命令时…

16. BootStrap

文章目录一、Bootstrap1、概念2、快速入门二、响应式布局三、CSS样式和JS插件1、全局CSS样式2、组件1. 导航条2. 分页条3、插件1. 轮播图四、案例1、案例描述2、案例分析3、实现一、Bootstrap 1、概念 * 概念&#xff1a; 一个前端开发的框架&#xff0c;Bootstrap&#xff0…

Linux网络配置(如何设置静态IP?如何设置查看主机名?)

文章目录Linux网络配置一、网络地址配置1.1. 查看网络地址1.2. 测试两个地址是否连接1.3. Linux系统的网络配置二、主机名以及hosts映射2.1. 查看和设置主机名2.2. hosts映射2.3. DNSLinux网络配置 一、网络地址配置 如果在一台Windows电脑上安装了Linux虚拟机&#xff0c;那…

颤抖开篇,从php角度谈谈IO模型(BIO)

颤抖开篇&#xff0c;从php角度谈谈IO模型&#xff08;BIO&#xff09; IO 是什么? 在计算机系统中I/O就是输入&#xff08;input&#xff09;和输出&#xff08;Output&#xff09;的意思。针对不同的操作对象&#xff0c;可以划分为磁盘I/O模型&#xff0c;网络I/O模型&am…

开发神器VSCode配置C/C++编译环境

hi&#xff0c;小伙伴们大家好&#xff0c;今天给大家介绍一款程序员常用的开发神器VSCode&#xff0c;想必大家肯定有所了解&#xff0c;也有很多小伙伴在日常工作中经常使用。当木荣君初次见到VSCode时&#xff0c;真正的被它惊艳到了&#xff0c;可以说是一见钟情。从此就爱…

13.6-14.8读书笔记

13.6 对象移动 13.6.1 右值引用 概念: 为了支持移动操作,新标准引入了的一种新的引用类型.所谓右值引用就是必须绑定到右值的引用. 通过&&来获得右值引用 int i 42;int &r i;int &&rr i; // 错误,不能将一个右值引用绑定到一个左值上int &r3 …

【python基础_05】面向对象

文章目录1. 类和对象1.1 使用对象组织数据的模版1.2 成员变量和成员方法1.3 实现代码2. 内置方法&#xff08;魔术方法&#xff09;2.1 构造方法&#xff1a;__init__&#xff08;&#xff09;1. 类和对象 1.1 使用对象组织数据的模版 1.2 成员变量和成员方法 1.3 实现代码 1…

jupyter notebook无法启动内核

jupyter notebook无法启动内核问题概述方法一使用Window PowerShell方法二更改文件路径重新启动内核参考问题概述 遇到的问题是在使用jupyter的时候无法正常运行,所以在这里尝试一些办法,在这里进行记录,希望能够帮助到大家 方法一 使用Window PowerShell 首先第一个方法就…

Java IO流 - 释放资源的方式

资源释放的方式 书接上文, 在上一篇文章我们做过一个文件拷贝的练习, 但是在联系中是有释放资源隐患的的, 例如在下面代码中, 在文件释放之前有许多行的逻辑代码; 如果这许多行的逻辑代码有报错, 导致程序不运行, 那么资源就得不到释放 public static void main(String[] args)…

Crack:ActiveReportsJS 3.2.2 EN:ActiveReportsJS

ActiveReportsJS - 高级 JavaScript 报告解决方案 ActiveReportsJS 是一种用于在前端应用程序中可视化数据的报告解决方案。Ω578867473自定义报告布局并将我们的报告设计器和查看器组件集成到 Web 应用程序中&#xff0c;以便在任何平台上预览、导出或打印报告。 使用我们的跨…

WPF+ASP.NET SignalR实现动态折线图

在实际业务中&#xff0c;当后台数据发生变化&#xff0c;客户端能够实时的收到通知&#xff0c;而不是由用户主动的进行页面刷新才能查看&#xff0c;这将是一个非常人性化的设计。有没有那么一种场景&#xff0c;后台数据明明已经发生变化了&#xff0c;前台却因为没有及时刷…