所有分类
  • 所有分类
  • 未分类

Java多线程-三种写法(Thread、Runnable、Callable)

简介

本文介绍Java多线程的三种写法(Thread、Runnable、Callable)。

写法1:继承 Thread 类

package com.example.a;

class TestThread extends Thread {
    private String name;

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

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(name + "运行,i = " + i);
        }
    }
}

public class Demo {
    public static void main(String[] args) {
        Thread thread1 = new TestThread("线程 A");
        Thread thread2 = new TestThread("线程 B");

        // 不能使用run(),因为它不会去启动多线程
        thread1.start();
        thread2.start();
    }

}

运行结果

线程 A运行,i = 0
线程 B运行,i = 0
线程 A运行,i = 1
线程 B运行,i = 1
线程 B运行,i = 2
线程 B运行,i = 3
线程 B运行,i = 4
线程 B运行,i = 5
线程 B运行,i = 6
线程 B运行,i = 7
线程 B运行,i = 8
线程 A运行,i = 2
线程 A运行,i = 3
线程 B运行,i = 9
线程 A运行,i = 4
线程 A运行,i = 5
线程 A运行,i = 6
线程 A运行,i = 7
线程 A运行,i = 8
线程 A运行,i = 9

写法2:实现 Runnable 接口

实例

package com.example.a;

class TestThread implements Runnable {
    private String name;

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

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(name + "运行,i = " + i);
        }
    }
}

public class Demo {
    public static void main(String[] args) {
        TestThread thread1 = new TestThread("线程 A");
        TestThread thread2 = new TestThread("线程 B");

        Thread t1 = new Thread(thread1);
        Thread t2 = new Thread(thread2);
        t1.start();
        t2.start();
    }

}

运行结果

线程 B运行,i = 0
线程 B运行,i = 1
线程 A运行,i = 0
线程 B运行,i = 2
线程 B运行,i = 3
线程 B运行,i = 4
线程 B运行,i = 5
线程 B运行,i = 6
线程 B运行,i = 7
线程 A运行,i = 1
线程 A运行,i = 2
线程 A运行,i = 3
线程 A运行,i = 4
线程 A运行,i = 5
线程 A运行,i = 6
线程 A运行,i = 7
线程 A运行,i = 8
线程 A运行,i = 9
线程 B运行,i = 8
线程 B运行,i = 9

Thread类和Runnable接口的区别

如果一个类继承Thread类,则不适合于多个线程共享资源,而实现了Runnable接口,就可以方便地实现资源共享。

例1:继承Thread类不能资源共享

package com.example.a;

class TestThread extends Thread {
    private int ticket = 5;

    public void run() {
        for (int i = 0; i < 100; i++) {
            if (ticket > 0) {
                System.out.println("卖票:ticket = " + ticket--);
            }
        }
    }
}

public class Demo {
    public static void main(String[] args) {
        Thread thread1 = new TestThread();
        Thread thread2 = new TestThread();

        // 不能使用run(),因为它不会去启动多线程
        thread1.start();
        thread2.start();
    }
}

运行结果(2个线程却分别卖了各自的5张票,并没有达到资源共享的目的。)

卖票:ticket = 5
卖票:ticket = 5
卖票:ticket = 4
卖票:ticket = 3
卖票:ticket = 4
卖票:ticket = 2
卖票:ticket = 1
卖票:ticket = 3
卖票:ticket = 2
卖票:ticket = 1

例2:实现Runnable接口可以资源共享

package com.example.a;

class TestThread implements Runnable {
    private int ticket = 5;

    public void run() {
        for (int i = 0; i < 100; i++) {
            if (ticket > 0) {
                System.out.println("卖票:ticket = " + ticket--);
            }
        }
    }
}

public class Demo {
    public static void main(String[] args) {
        TestThread thread1 = new TestThread();
        Thread t1 = new Thread(thread1);
        Thread t2 = new Thread(thread1);

        // 不能使用run(),因为它不会去启动多线程
        t1.start();
        t2.start();
    }
}

运行结果(启动了2个线程,2个线程一共卖了5张票,即ticket属性被所有的线程共享。(本处暂不考虑线程安全性)) 

卖票:ticket = 5
卖票:ticket = 3
卖票:ticket = 2
卖票:ticket = 1
卖票:ticket = 4

写法3:实现 Callable接口

使用Runnable接口实现的多线程可以避免单继承局限,但其run()方法不能返回操作结果。为解决此问题,从JDK1.5开始对多线程的实现提供了一个新接口:java.util.concurrent.Callable。

Callable接口定义如下:

public interface Callable<V> {
    public V call() throws Exception;
}

Callable接口有一个call()方法,在call()方法上可实现线程操作数据的返回,返回的数据类型由Callable接口上的泛型类型动态决定。

package com.example.a;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

class TestThread implements Callable<String> {
    private int ticket = 3;

    @Override
    public String call() {
        for (int i = 0; i < 100; i++) {
            if (ticket > 0) {
                System.out.println("卖票:ticket = " + ticket--);
            }
        }

        return "票已卖完";
    }
}

public class Demo {
    public static void main(String[] args) {
        TestThread thread1 = new TestThread();
        TestThread thread2 = new TestThread();
        FutureTask<String> task1 = new FutureTask<>(thread1);
        FutureTask<String> task2 = new FutureTask<>(thread2);

        //FutureTask是 Runnable接口子类,所以可以使用Thread类的构造来接收task对象
        new Thread(task1).start();
        new Thread(task2).start();
        try {
            System.out.println("线程1的返回结果: " + task1.get());
            System.out.println("线程2的返回结果: " + task2.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

执行结果

卖票:ticket = 3
卖票:ticket = 3
卖票:ticket = 2
卖票:ticket = 1
卖票:ticket = 2
卖票:ticket = 1
线程1的返回结果: 票已卖完
线程2的返回结果: 票已卖完
1

评论0

请先

显示验证码
没有账号?注册  忘记密码?

社交账号快速登录