java中实现多线程的三种方式

1、实现多线程的方法:
在java中实现多线程的两途径:继承Thread类,实现Runable接口(Callable)
2、继承Thread类实现多线程:

继承类Thread是支持多线程的功能类,只要创建一个子类就可以实现多线程的支持。

所有的java程序的起点是main方法,所以线程一定有自己的起点,那这个起点就是run方法;因为多线程的每个主体类之中必须重写Thread的run方法。

public void run()

这个run方法没有返回值,那就说明线程一旦开始就一直执行不能返回内容。

2.1线程案例:

编写一个测试线程类继承Thread 在run方法中写一个循环输出语句;

分析:创建多个测试类启动线程,多个线程回想进程一样,轮流抢占资源,所以多线程程序应该是多个线程彼此交替执行;

class TestThread extends Thread{//内部类
    String name;

    TestThread( String name){
        this.name=name;
    }
    @Override
    public void run(){
        for(int i=1;i<10;i++) {
            System.out.print(name + i);
        }
    }

}

public class MyThread  {

    public static void main(String[] args) {
        new TestThread("A").run();
        new TestThread("B").run();
        new TestThread("C").run();
    }
}

上面是调用Thread的run方法,但是查看日志输出并不是交替输出如下

A1A2A3A4A5A6A7A8A9B1B2B3B4B5B6B7B8B9C1C2C3C4C5C6C7C8C9

本线程类的功能是进行循环的输出操作,所有的线程与进程是一样的,都必须轮流去抢占资源,所以多线程的执行应该是多个线程彼此交替执行,也就是说如果调用了run方法,那么并不能够启动多线程,多线程启动的唯一方法是调用Thread的start方法(调用此方法执行的是run方法体)。

修改如下:

public class MyThread  {

    public static void main(String[] args) {
        new TestThread("A").start();
        new TestThread("B").start();
        new TestThread("C").start();
    }
}

运行结果

B1C1A1C2C3B2B3C4A2A3A4A5A6A7A8A9C5C6C7B4B5B6B7B8B9C8C9

疑问?为什么多线程的启动不是调用run方法而必须调用start方法?

找到java的源代码:在jdk安装的目录找到src压缩包解压,在java.lang包里的Thread的start方法如下:

public synchronized void start() {
        
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

    private native void start0();

在start方法里,开始的地方有IllegalThreadStateException异常抛出,防止线程启动重复。

发现在start方法里面要调用一个start0方法,而且此方法的结构和抽象方法类似,使用了native声明,在Java开发里面有一门技术称为JNI技术(Java Native Interface),这门技术的特点:是使用Java调用本机操作系统提供的函数。但是有个缺点:不能够离开特定的操作系统。

总结:使用Thread类的start方法不仅仅启动多线程的执行代码,还要从不同操作系统中分配资源。

3、实现Runnable

Java具有单继承局限,所有的Java程序针对类的继承都应该是回避,那么线程也一样,为了解决单继承的限制,因此才有Runnable接口代码如下:

@FunctionalInterface
public interface Runnable{
    public void run();
}

这个接口有点特殊是@FunctionalInterface注解修饰的,这是函数式接口,特征是:一个接口只有一个方法。

接口中的方法都是public权限,不存在默认权限。

使用方法:让一个类实现Runnable接口即可,并且也需要覆写run()方法。

疑问:但是此接口只有run方法,没有start方法,怎么启动多线程呢?

不管任何情况下,如果要想启动多线程一定要依靠Thread类完成,在Thread类中有参数是Runnable参数的构造方法:

  • Thread(Runnable target) 接收的是Runnable接口

可以创建一个参数是Runnable实现类的Thread类,调用start方法启动。

public class MyThread  {

    public static void main(String[] args) {
        new Thread(new TestThread("A")).start();
        new Thread(new TestThread("B")).start();
        new Thread(new TestThread("C")).start();
    }
}

总结:实现Runnable接口来写多线程的业务类,用Thread来启动多线程。