多线程

Posted Kirl z

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程相关的知识,希望对你有一定的参考价值。

1. Thread 类基础 api

修饰符和类型方法和描述
static ThreadcurrentThread() 返回对当前正在执行的线程对象的引用
static voidsleep(long millis) 使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。
static voidyield() 对调度程序的一个暗示,即当前线程愿意产生当前使用的处理器。
static intactiveCount() 返回当前线程的thread group及其子组中活动线程数的估计。
public class ThreadDemo {
	public static void main(String[] args) {
		Thread thread = Thread.currentThread();
		System.out.println(thread.getName());
	}
}

2. 理解多线程效率与线程数, 任务量, 系统可用资源的关系

通过控制变量法测试

如何确定线程数?
总任务量恒定, 系统可用资源恒定的情况下:
线程创建是比较耗时的操作, 单个任务量比较小, 还不如一个线程就完成, 不用开启新的线程
在这里插入图片描述

public class ThreadAdv {

    public static void main(String[] args) {
        //循环10亿次,每次++运算
        //1.串行的方式:main线程运行两次
        long start = System.nanoTime();
        loop();
        loop();
        long end = System.nanoTime();
        System.out.printf("串行执行耗时:%s毫秒%n", (end-start)/1000/1000);

        //2.并行的方式:main线程,子线程同时执行loop方法
        long start2 = System.nanoTime();

        new Thread(new Runnable() {
            @Override
            public void run() {
                loop();
            }
        }).start();

        loop();
        //计算时间,需要让子线程,main线程loop都执行完
        //当前main和main线程中创建的子线程,活跃线程数>1,main线程就一直让步
        //子线程执行完,main线程才能继续向下执行
        //使用activeCount在idea要用debug方式运行
        while(Thread.activeCount()>1) Thread.yield();
        long end2 = System.nanoTime();
        System.out.printf("并行执行耗时:%s毫秒%n", (end2-start2)/1000/1000);

    }
    private static void loop(){
        int m = 0;
        for (int i = 0; i < 10_0000_0000; i++) {
            m++;
        }
    }
}

3. 线程中断

3.1 使用(共享)标志位

可以实现某种程度上的, 在满足条件 (中断线程的条件: 如转账发现诈骗) 情况下, 中断一个线程

public class FlagStopThread {

    //使用标志位标识是否继续执行线程中的任务,true中断,false继续执行
    private static volatile boolean isStop = false;

    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("开始转账");
                try {
                    while (!isStop){
                        System.out.println("转账ing...");
                        Thread.sleep(10000);
                    }
                    System.out.println("停止转账");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        Thread.sleep(3*1000);
        //发现是诈骗犯,需要停止转账
        isStop = true;
    }
}

但存在问题:
如果一个线程正处于阻塞状态 (需要满足一定条件如sleep休眠一定时间, 才能恢复), 就无法快速 (立即) 的中断线程

3.2 调用 interrupt() 方法

Thread 类中, 保存有一个中断表示为, 初始值 = false (没有被中断)

类型描述
voidinterrupt() 中断这个线程

中断某个线程:

  1. 线程中断标志位 = true
  2. 线程要不要中断, 线程定义任务的代码自行决定
  3. 如果线程处于阻塞状态 (调用多线程阻塞 api 方法, 显示抛出 InterruptedException 的方法)
    直接提前让线程从阻塞状态转变为就绪态, 在系统调度执行后, 以抛异常的方式继续执行 (此时线程的中断标志位会重置为 false)
public class InterruptedResetFlag {

    public static void main(String[] args) {
        test1();
        test2();
    }

    public static void test1(){
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                //标志位=true
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().isInterrupted());
                }
                //打印结果:10次true
            }
        });
        t.start();
        t.interrupt();//1,标志位=true
    }

    public static void test2(){
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                //标志位=true
                for (int i = 0; i < 10; i++) {
                    //i==0, 打印true,重置标志位=false
                    System.out.println(Thread.interrupted());
                }
                //打印结果:第一次true,后边9次false
            }
        });
        t.start();
        t.interrupt();//1,标志位=true
    }
}

3.3 interrupted() 方法

线程可以获取中断标志位, 通过循环判断, 来决定是否需要中断

类型描述
static booleaninterrupted() 测试当前线程是否中断
booleanisInterrupted() 测试这个线程是否被中断
public class InterruptThread {

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("开始转账");
                    while (!Thread.currentThread().isInterrupted()){
                        System.out.println("转账ing...");
                        Thread.sleep(10000);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        Thread.sleep(3*1000);
        t.interrupt();
    }
}

4. 线程等待

类型描述
voidjoin() 等待这个线程死亡
voidjoin(long millis) 等待这个线程死亡最多 millis 毫秒

线程引用对象 .join() / 线程引用对象.join(long)
当前线程等待, 知道满足…条件:

  1. 无参的方法, 就是线程执行完毕
  2. 有参的方法, 是线程执行完毕和时间到达任意一个满足

满足以后, 当前线程继续往下执行

public class ThreadJoin {

    public static void main(String[] args) throws InterruptedException {
        test1();
        test2();
    }

    public static void test1() throws InterruptedException {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("t run");
            }
        });
        t.start();
        t.join();//main线程一直阻塞等待,直到t线程执行完毕,main线程再继续执行
        System.out.println("main running...");
    }

    public static void test2() throws InterruptedException {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("t start");
                    Thread.sleep(3000);
                    System.out.println("t end");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        t.join(1000);//main线程一直阻塞等待,直到t线程执行完毕,main线程再继续执行
        System.out.println("main running...");
    }
}

5. 线程状态

Java 中线程的所有状态:

NEW (创建)
RUNNABLE (可运行态)
BLOCKED (阻塞态)
WAITING (等待)
TIMED_WAITING (超时等待)
TERMINATED (终止)

在这里插入图片描述

  • yield() 只是让出 CPU,并不会改变自己的状态, 线程让步。

以上是关于多线程的主要内容,如果未能解决你的问题,请参考以下文章

线程学习知识点总结

多个请求是多线程吗

python小白学习记录 多线程爬取ts片段

多线程编程

多线程编程

python多线程