java多线程编程

  在 Java 的 JDK 开发包中,已经自带了对多线程技术的支持,可以方便地进行多线程编程。Java 实现多线程编程的方式主要有三种:(1)通过实现 Runnable 接口;(2)通过继承 Thread 类;(3)通过 Callable 和 Future 创建线程。

  下面详细介绍下这三种具体实现方式。

通过实现 Runnable 接口来创建线程

  创建线程的一种方法是,创建一个实现 Runnable 接口的类,并使用其对象创建一个Thread 实例。

  Runnable接口只有一个抽象方法 run(),其声明如下:

    public abstract void run();

  因此,实现 Runnable接口的类需要重写 run() 方法,该 run() 方法就是线程将要执行的方法。

  实现 Runnable 接口的程序还需要创建一个 Thread 对象,并将 Runnable 对象与 Thread 对象相关联。

  使用 Runnable 接口启动线程的基本步骤如下:

  1. 创建一个 Runnable 对象。
  2. 使用该 Runnable 对象创建一个 Thread 对象。
  3. 调用该 Thread 对象的 start() 方法启动线程。

   

   下面是一个简单的示例程序:

public class MyRunnable implements Runnable {
    private String threadName;
    
    public MyRunnable(String threadName) {
        this.threadName = threadName;
        System.out.println("Creating thread: " + threadName);
    }

    @Override
    public void run() {
        System.out.println("Thread[" + threadName + "] running...");
        
        try {
            for (int i = 0; i < 10; i++) {
                System.out.println("Thread[" + threadName + "] running..., " + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("Thread[" + threadName + "] exiting...");
    }
}

public class Test {
    public static void main(String[] args) {
        Runnable runnable1 = new MyRunnable("RunnableThread-1");
        Thread thread1 = new Thread(runnable1);
        
        Runnable runnable2 = new MyRunnable("RunnableThread-2");
        Thread thread2 = new Thread(runnable2);
        
        thread1.start();
        thread2.start();
    }
}

  运行结果如下:

Creating thread: RunnableThread-1
Creating thread: RunnableThread-2
Thread[RunnableThread-1] running...
Thread[RunnableThread-1] running..., 0
Thread[RunnableThread-2] running...
Thread[RunnableThread-2] running..., 0
Thread[RunnableThread-2] running..., 1
Thread[RunnableThread-1] running..., 1
Thread[RunnableThread-2] running..., 2
Thread[RunnableThread-1] running..., 2
Thread[RunnableThread-1] running..., 3
Thread[RunnableThread-2] running..., 3
Thread[RunnableThread-1] running..., 4
Thread[RunnableThread-2] running..., 4
Thread[RunnableThread-1] running..., 5
Thread[RunnableThread-2] running..., 5
Thread[RunnableThread-2] running..., 6
Thread[RunnableThread-1] running..., 6
Thread[RunnableThread-2] running..., 7
Thread[RunnableThread-1] running..., 7
Thread[RunnableThread-2] running..., 8
Thread[RunnableThread-1] running..., 8
Thread[RunnableThread-2] running..., 9
Thread[RunnableThread-1] running..., 9
Thread[RunnableThread-2] exiting...
Thread[RunnableThread-1] exiting...

 

通过继承Thread类来创建线程

  我们先来看下 Thread 类的声明:

public class Thread implements Runnable {
  ....
}

  可以看到,Thread类实现了 Runnable 接口,因此通过继承Thread类创建线程跟通过实现 Runnable 接口来创建线程这两种方法没有本质的区别。

  显而易见,创建线程的第二种方法就是创建一个新的类,该类继承 Thread 类,然后创建一个该类的实例即可。继承类必须重写 run() 方法,该方法是新线程的入口,线程的业务代码需要放到 run() 方法中。在调用Thread实例的 start() 方法后,该run() 方法就会执行。

  示例程序:

public class MyThread extends Thread {
    private String threadName;

    public MyThread(String threadName) {
        this.threadName = threadName;
        System.out.println("Creating thread: " + threadName);
    }
    
    @Override
    public void run() {
        System.out.println("Thread[" + threadName + "] running...");
        
        try {
            for (int i = 0; i < 5; i++) {
                System.out.println("Thread[" + threadName + "] running..., " + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("Thread[" + threadName + "] exiting...");
    }
}

public class Test {
    public static void main(String[] args) {
        Thread thread1 = new MyThread("Thread-1");
        Thread thread2 = new MyThread("Thread-2");
        
        thread1.start();
        thread2.start();
    }
}

  运行结果如下:

Creating thread: Thread-1
Creating thread: Thread-2
Thread[Thread-1] running...
Thread[Thread-1] running..., 0
Thread[Thread-2] running...
Thread[Thread-2] running..., 0
Thread[Thread-2] running..., 1
Thread[Thread-1] running..., 1
Thread[Thread-2] running..., 2
Thread[Thread-1] running..., 2
Thread[Thread-2] running..., 3
Thread[Thread-1] running..., 3
Thread[Thread-1] running..., 4
Thread[Thread-2] running..., 4
Thread[Thread-1] exiting...
Thread[Thread-2] exiting...

  使用继承 Thread 类的方式实现多线程,最大的局限就是不支持多继承,因为 Java 语言的特点就是单继承,如果你的类还需要继承于其他类,就需要使用实现 Runnable 接口的方式。这两种方式创建的线程在工作时的性质是一样的,没有本质的区别。

 

通过 Callable 和 Future 创建线程

   Callable是个泛型接口,其声明如下:

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

  Callable 接口只有一个call()方法,因此实现 Callable 接口的类需要重写该 call() 方法,这个方法就是线程的执行方法,新创建线程的业务代码都放在这里。Callable 接口还有个类型参数,它是 call() 方法的返回值类型,也就是线程的返回值类型。与前两种创建线程的方式不同,这种创建线程的方式允许线程返回一个执行结果,如果新线程需要返回执行结果的话就要使用这种方式来创建线程。线程的执行结果是通过 FutureTask 对象的 get() 方法获取的。

  FutureTask是个泛型类,其类型参数必须与Callable接口的类型参数一致,这个类型就是线程的返回值类型。FutureTask 实现了RunnableFuture接口,而RunnableFuture接口继承了Runnable和Future接口,也就是说FutureTask既是Runnable,也是Future,因此FutureTask具备Runbale的 run() 方法执行异步任务,也可以像Future一样能够控制任务的执行,并获取任务的执行结果。

  使用 Callable 和 Future 创建线程的步骤如下:

  1. 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并返回执行结果。
  2. 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了 Callable 对象的 call() 方法的返回值。
  3. 使用 FutureTask 对象作为 Thread 对象的 target,创建并启动新线程。
  4. 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。

   示例代码:

public class MyCallable implements Callable<String> {
    private String threadName;

    public MyCallable(String threadName) {
        this.threadName = threadName;
        System.out.println("Creating thread: " + threadName);
    }

    @Override
    public String call() throws Exception {
        System.out.println("Thread[" + threadName + "] running...");
        return "Hello world!";
    }
}

public class Test {
    public static void main(String[] args) {        
        MyCallable callable = new MyCallable("CallableThread");
        FutureTask<String> futureTask = new FutureTask<String>(callable);
        
        new Thread(futureTask).start();
        
        try {
            String str = futureTask.get();
            System.out.println(str);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

  运行结果如下:

Creating thread: CallableThread
Thread[CallableThread] running...
Hello world!

 

创建线程的三种方式的对比

  • 使用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。
  • 使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。
  • 使用实现 Callable 接口的方式创建线程时,可以异步获取线程的执行结果。

 

参考:

  https://blog.csdn.net/fangqun663775/article/details/78961417
  http://c.biancheng.net/view/1159.html

posted on 2019-07-19 16:57  泣血  阅读(493)  评论(0编辑  收藏  举报

导航