60 多个实例讲解,完全搞懂 Java 多线程! - 知乎

https://zhuanlan.zhihu.com/p/107479862java


​JAVA 最难学的部分是哪里?不少朋友都会说:「 java 多线程 」程序员

随着业务量和数据的增长,企业不可避免地会使用多线程的方式处理数据。在 Java 职位的面试中,多线程也是必考的高阶知识点之一。能够说,java多线程是衡量一名 Java 程序员是否资深的关键标准之一。web

今天,咱们就来学习一下 Java 多线程的概念吧!面试

(点击课程连接,开启实验环境,边学边练才是更有效的学习方式)数据库

Java 多线程技术实战www.shiyanlou.com图标

多进程与多线程的概念

初步建立多线程,理清多线程的概念。多线程

知识点

  • 多线程的概念
  • 建立多线程 —— 继承 Thread
  • 建立多线程 —— 实现 Runnable
  • 建立多线程 —— 实现 Callable

多进程和多线程的概念

进程是程序在计算机上的一次执行活动。当你运行一个程序,你就启动了一个进程。凡是用于完成操做系统的各类功能的进程就是系统进程,而全部由你启动的进程都是用户进程。

多进程

进程是程序在计算机上的一次执行活动。当你运行一个程序,你就启动了一个进程。凡是用于完成操做系统的各类功能的进程就是系统进程,而全部由你启动的进程都是用户进程。异步

如图所示每个正在运行的 .exe 程序都是一个进程。ide

多线程

进程就是有一个或多个线程构成的。而线程是进程中的实际运行单位,是独立运行于进程之中的子任务。是操做系统进行运算调度的最小单位。可理解为线程是进程中的一个最小运行单元。函数

进程和线程之间的关系

一个进程下包含 N 个线程。学习

举例说明:玩英雄联盟的时候,打开客户端便启动了许多个线程:排队队列线程、好友聊天线程、正在支付线程。在英雄联盟这一个进程之下便启动了 N 个线程。

咱们初学 java 边写代码的时候,一般使用 main 方法进行运行,此时 main 方法执行的即是一个主线程,而所谓的多线程,便是在主线程执行的过程当中,同时执行其余的线程。可是同时执行多个线程容易出现报错现象,例如同时同分同秒,两个线程同时修改一个 txt、数据库表文件,或第一个线程没有修改完 txt、数据库表文件,第二个线程同时也去修改。这即是线程之间的混乱、资源竞争、脏读,即是程序员须要去解决的疑难杂症。

建立多线程 —— 继承 Thread

java 世界中有两种方式建立多线程:

java 世界中有两种方式建立多线程,分别是继承 Thread 类,实现 Runnable 接口。

继承 Thread 类方式建立多线程

第一步:在 webide 上右键单击菜单,选择 New File 建立新文件。

第二步:建立文件名为 test0.java

第三步:编写 test0.java 中继承 Thread 类方式建立多线程的代码以下所示:

public class test0 {

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

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("hello myThread" + Thread.currentThread().getName());
    }
}

第四步:编译 test0.java 代码:

javac test0.java

编译以后,会产生咱们所编写的 test0 类与 MyThread 类

第五步:运行 test 代码:java test0

建立多线程 —— 实现 Runnable

只须要把《建立多线程 —— 继承 Thread》中代码修改为以下所示便可,其它操做不变:

public class test0 {

    public static void main(String[] args) {

        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}

class MyRunnable implements Runnable{
    @Override
    public void run(){
        System.out.println("hello myRunnable" + Thread.currentThread().getName());
    }
}

执行结果以下所示:

一般状况下,若是建立的线程类已经含有父类时候,此时因为 Java 语法结构不支持多继承的缘由,不可以再次继承 Thread 类,此时则须要使用实现 Runnable 接口的方式来应对如此场景。另外值得说明的是,Thread 类也实现了 Runnable 接口。

实现多线程传参 —— 有参构造

因为多线程是由继承 Thread 或实现 Runnable 并重写 run() 方法,经过 thread.start() 进行运行的,而自己重写的 run() 方法是不具有传参能力的,那我新建的线程就接受不到我所想传入的参数了么?

建立 study1.java 文件

class ThreadA extends Thread{

    private String age;

    public ThreadA(String age){
        this.age = age;
    }
    @Override
    public void run() {
        System.out.println("age=" + age);
    }
}

public class study1 {
    public static void main(String[] args) {
        String age = new String("12");
        ThreadA a = new ThreadA(age);
        a.start();
    }
}

不管 extendsThread 仍是 implementsRunnable ,传参都须要使用线程初始化的有参构造形式,达到多线程传参的目的。也能够作到重载有参构造,传入各式对象。

study1 运行结果

实现多线程返回值 —— 实现 Callable<V>

一般意义上理解确实 Java 实现多线程的方式有继承 Thread 和实现 Runnable,可是若是想实现多线程而且具备返回值的状况下,须要实现 Callable<V> 接口,这个接口是 JDK1.5 版本之后才出现的接口。

建立 study2.java

建立 study2.java 文件,利用实现 Callable<V> 进行返回,代码以下所示:

import java.util.concurrent.Callable;

public class study2 {
    public static void main(String[] args) {
        MyCallable MyCallable = new MyCallable("张方兴");
        String call = null;
        try {
            call = MyCallable.call();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(call);
    }
}

class MyCallable implements Callable<String>{

    private String name;

    public MyCallable(String name) {
        this.name = name;
    }

    @Override
    public String call() throws Exception {
        return "call:" + name;
    }
}

study2 运行结果

Callable<V> 接口详解

通常继承 Thread 的类,含有 .start() 函数,因此直接可使用 .start() 函数进行启动。实现 Runnable 的类,须要经过 newThread(myRunnable).start(); 的方式进行启动,即实现 Runnable 的类只是作好了一段多线程所需执行的内容,自身并无执行的能力,须要经过 Thread 类的 .start() 函数进行启动。实现 Callable<V> 的接口,含有 .call() 函数,因此能够直接使用 .call() 函数进行启动,另外值得说明的是, Callable<V> 函数具备返回值,返回值为定义类时使用的 <V> 类型,其定义是其返回。 Callable<V> 接口定义以下所示:

@FunctionalInterface
public interface Callable<V> {
    /**  * Computes a result, or throws an exception if unable to do so.  *  * @return computed result  * @throws Exception if unable to compute a result  */
    V call() throws Exception;
}

Callable<V> 用于指示接口类型声明是由 Java 语言规范定义的功能接口。从概念上讲,函数接口只有一个抽象方法。由于 java.lang.reflect.Method#isDefault()default methods 有一个实现,因此它们不是抽象的。若是接口声明一个抽象方法重写 java.lang.Object 的一个公共方法,则该方法也不计入接口的抽象方法计数,由于接口的任何实现都将具备来自 java.lang.Object 或其余位置的实现。另外注意,函数接口的实例可使用 lambda 表达式、方法引用或构造函数引用建立。

Callable<V> 在须要使用返回值的状况下,程序是同步运行的Callable<V> 。其它状况下,程序是异步运行的

完整课程内容,请在实验楼边操做边学习。

Java 多线程技术实战www.shiyanlou.com图标
相关文章
相关标签/搜索