Java教程

Java多线程高并发

本文主要是介绍Java多线程高并发,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1.线程概述

1.1 线程相关概念
进程(Process):
是计算机中的程序关于某数据集合上的一次运行活动,是操作系统进行资源分配与调度的基本单位,可以把进程理解为操作系统当中正在运行的一个程序

线程(Thread):
是进程的一个执行单元,一个线程就是进程中一个单一顺序的控制流,线程就是进程的一个执行分支,进程是线程的容器,一个进程至少有一个线程,一个进程中也可以有多个线程,在操作系统中是以进程为单位分配资源,如:虚拟存储空间、文件描述符等,每个线程都有各自的线程栈,java内存分为栈区、堆区、方法区三个区域,栈区每个线程都有自己的寄存器环境,都有自己的线程本地存储

主线程和子线程:
JVM虚拟机启动时会创建一个主线程,该主线程负责执行main方法,主线程就是运行main方法的线程,Java中的线程不是孤立的,线程之间存在一些联系,如果在A线程中创建了B线程,称B线程为A线程的子线程,相应的A线程就是B线程的父线程

串行,并发与并行
假设有三个任务:
任务A准备5分钟,等待10分钟
任务B准备2分钟,等待8分钟
任务C准备10分钟

串行:
在这里插入图片描述
串行Sequential:先做任务A,完成后在做任务B,完成后再做任务C,所有的任务逐个完成,共耗时(任务A 10+5)+(任务B 2+8)+ (任务C 10)= 35分钟

并发:
在这里插入图片描述
并发(Concurrent):先做任务A,准备了5分钟后,在等待A完成的这段时间内就开始做任务B,任务B准备了2分钟后,在等待B完成的过程中开始做任务C,10分钟后任务C结束,共耗时 5 + 2 + 10 = 17分钟

并发可以提高以事务的处理效率,即使在一段时间内可以处理或者完成更多的事情

并行:
在这里插入图片描述
并行(Parallel):三个任务同时开始,总耗时取决于需要时间最长的那个任务,总耗时就是任务A准备+等待时间15分钟

并行是一种更为严格或者理想的并发

从硬件的角度来说:
如果是单核CPU,一个处理器一次只能执行一个线程的情况下,处理器可以使用时间片轮转技术,可以让CPU快速的在各个线程之间进行切换,对于用户来说,感觉是三个线程在同时执行,其实是切换的速度比较快
如果是多核CPU,可以为不同的线程分配不同的CPU内核

1.2线程的创建与启动

在Java当中,创建一个线程就相当于创建一个Thread类(子类)对象(实例化)
Thread类有两个常用的构造方法:Thread()与Thread(Runnable),对应的创建线程的两种方式:
(1)定义Thread类的子类
(2)定义一个Runnable接口的实现类
这两种创建线程的方式没有本质的区别

创建线程的第一种方式:继承Thread类

演示执行顺序如下:
先创建一个MyThread01类:

//1)定义一个类继承Thread
public class MyThread01 extends Thread {
    //2)重写Thread父类中的run方法
    //run()方法体中的代码就是子线程要执行的任务
    @Override
    public void run() {
        System.out.println("这是子线程打印的内容");
    }
}

再创建一个MyThreadTest测试类:

public class MyThreadTest {
    public static void main(String[] args) {
        System.out.println("JVM启动main线程,main线程执行main方法");
        //3)创建子线程对象
        MyThread01 myThread01 = new MyThread01();
        //4)启动线程
        myThread01.start();
        System.out.println("main线程后面其他的代码");
    }
}

调用线程的start()方法来启动线程,启动线程的实质就是请求JVM运行相应的线程
这个线程具体在什么时候运行,由线程调度器(Scheduler)决定
注意:
1.start()方法调用结束并不意味着子线程开始运行
2.新开启的线程会执行run()方法
3.如果开启了多个线程,start()调用的顺序并不一定就是线程启动的顺序
4.多线程运行结果与代码执行顺序或者调用顺序无关

演示线程运行结果的随机性:
创建一个Test测试类:

//演示线程运行结果的随机性
public class Test {
    public static void main(String[] args) {
        MyThread02 myThread02 = new MyThread02();
        //开启子线程
        myThread02.start();
        //当前是main线程
        try {
            for (int i = 0; i <= 10; i++) {
                System.out.println("main--:" + i);
                //线程会休眠,单位是毫秒,1秒 = 1000ms
                int time = (int) (Math.random() * 1000);
                Thread.sleep(time);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

创建一个主线程类:

public class MyThread02 extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i <= 10; i++) {
                System.out.println("sub thread:" + i);
                //线程会休眠,单位是毫秒,1秒 = 1000ms
                int time = (int) (Math.random() * 1000);
                Thread.sleep(time);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
创建线程的第二种方式:Runnable接口

创建Runnable接口类:

/**
 * 当线程已经有父类了,就不能用继承Thread类的形式创建线程,可以使用Runnable接口的形式
 * 1)定义类实现Runnable接口
 */
public class MyRunnable implements Runnable {
    //2)重写Runnable接口中的抽象方法run(),run方法他就是子线程要执行的代码
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("sub thread:" + i);
        }
    }
}

创建测试类:

//测试实现Runnable接口的形式创建线程
public class Test {
    public static void main(String[] args) {
        //3)创建Runnable接口的实现类对象
        MyRunnable myRunnable = new MyRunnable();
        //4)创建线程对象,开启线程
        new Thread(myRunnable).start();
        //当前是main线程
        for (int i = 0; i < 1000; i++) {
            System.out.println("main:" + i);
        }
        //有时调用Thread(Runnable)构造方法时,实参也会传递匿名内部类对象
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 300; i++) {
                    System.out.println("sub-----------:" + i);
                }
            }
        });
        thread2.start();
    }
}

1.3 线程的常用方法

(1)currentThread()方法
Thread.currentThread()方法可以获得当前线程
Java中的任何一段代码都是执行在某个线程当中的,执行当前代码的线程就是当前线程
同一段代码可能被不同的线程执行,因此当前线程是相对的,Thread.currentThread()方法的返回值是在代码实际运行时的线程对象

实例如下:
创建一个测试类:

public class Test01 {
    public static void main(String[] args) {
        System.out.println("main方法中打印当前线程"
                + Thread.currentThread().getName());
        //创建子线程,调用SubThread01构造方法,在main线程中调用构造方法
        //所以构造方法中的当前线程就是main线程

        //启动子线程,子线程会调用run方法,所以当前线程就是输出为Thread-0子线程
        new SubThread01().start();

        //在main方法中直接调用run方法,没有开启新的线程
        //所以在run方法中的当前线程就是main线程
    }
}

创建一个线程类:

/**
 * 定义一个线程类
 * 分别在构造方法中和run方法中打印线程
 */
public class SubThread01 extends Thread {
    public SubThread01() {
        System.out.println("构造方法打印当前线程名称"
                + Thread.currentThread().getName());
    }

    @Override
    public void run() {
        System.out.println("run方法打印当前线程名称"
                + Thread.currentThread().getName());
    }
}

这篇关于Java多线程高并发的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!