Java中的多线程

来源:互联网 发布:python运行程序 编辑:程序博客网 时间:2024/05/22 06:37

在Java中一个很重要的基础就是线程,而每次提到线程大家必想到的是进程,所以在总结Java多线程之前我们先对进程和线程进行一下区分:

进程:一个计算机程序的运行实例,每个进程有独立的代码和数据空间(进程上下文),而一个进程中可以有多个线程;

线程:是进程中运行的一个实体,同一类线程共享代码和数据空间,每个下城有独立的运行栈;

但是它们都有五个运行的阶段:创建-->就绪-->运行-->阻塞-->终止;


在Java中多线程的启动主要有三种方式:继承Thread类重写该类的run()方法,实现Runnable接口;使用Callable和Future接口创建线程;下面就一一来看,这三种不同的启动方式的代码实现:

➷   扩展Thread类重写该类的run()方法

/** * 测试扩展Thread类实现的多线程程序* */ publicclass TestThread extends Thread{     public TestThread(String name) {        super(name);    }     publicvoid run() {        for(int i = 0;i<5;i++){            for(long k= 0; k <100000000;k++);            System.out.println(this.getName()+" :"+i);        }     }     publicstaticvoid main(String[] args) {        Thread t1 = new TestThread("阿三");        Thread t2 = new TestThread("李四");        t1.start();         t2.start();     } }
执行结果如下:

阿三 :0李四 :0 阿三 :1 李四 :1 阿三 :2 李四 :2 阿三 :3 阿三 :4 李四 :3 李四 :4 Process finished with exit code 0

➷  实现Runnable接口

<span style="font-size:18px;">/** * 实现Runnable接口的类* */ publicclass DoSomethingimplements Runnable {    private String name;    public DoSomething(String name) {        this.name = name;    }     publicvoid run() {        for (int i = 0; i < 5; i++) {            for (long k = 0; k < 100000000; k++) ;            System.out.println(name + ": " + i);        }     } }</span>
<span style="font-size:18px;">/** * 测试Runnable类实现的多线程程序* */ publicclass TestRunnable {    publicstaticvoid main(String[] args) {        DoSomething ds1 = new DoSomething("阿三");        DoSomething ds2 = new DoSomething("李四");        Thread t1 = new Thread(ds1);        Thread t2 = new Thread(ds2);        t1.start();         t2.start();     } }</span>
    执行的结果为:

李四: 0阿三: 0 李四: 1 阿三: 1 李四: 2 李四: 3 阿三: 2 李四: 4 阿三: 3 阿三: 4 Process finished with exit code 0

➷ 使用Callable和Future接口创建线程

具体是创建Callable接口的实现类,并实现call方法;使用Future Task类来包装Callable实现类的对象,且以此FutureTask 对象作为Thread对象的target来创建线程。

<span style="font-size:18px;">public class ThreadTest {    public static void main(String[] args) {        Callable<Integer> myCallable = new MyCallable();    // 创建MyCallable对象        FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); //使用FutureTask来包装MyCallable对象        for (int i = 0; i < 100; i++) {            System.out.println(Thread.currentThread().getName() + " " + i);            if (i == 30) {                Thread thread = new Thread(ft);   //FutureTask对象作为Thread对象的target创建新的线程                thread.start();                      //线程进入到就绪状态            }        }        System.out.println("主线程for循环执行完毕..");                try {            int sum = ft.get();            //取得新创建的新线程中的call()方法返回的结果            System.out.println("sum = " + sum);        } catch (InterruptedException e) {            e.printStackTrace();        } catch (ExecutionException e) {            e.printStackTrace();        }    }}class MyCallable implements Callable<Integer> {    private int i = 0;    // 与run()方法不同的是,call()方法具有返回值    @Override    public Integer call() {        int sum = 0;        for (; i < 100; i++) {            System.out.println(Thread.currentThread().getName() + " " + i);            sum += i;        }        return sum;    }}</span>
这时我们可以发现,在实现Callable接口的不再是run()方法了,而是call方法,这个call方法作为线程的执行体,同时还具有返回值!在创建新的线程时,是通过FutureTask来包装MyCallable对象,同时作为了Thread对象的target,下面是Future Task类的定义:

<span style="font-size:18px;"> public class FutureTask<V> implements RunnableFuture<V> {          //....      }  public interface RunnableFuture<V> extends Runnable, Future<V> {          void run();      }</span>
从上面的代码我们可以发现,Future Task 类实际上是同时实现了Runnable和Future接口,由此才使得其具有Future和Runnable双重特性。

上面主要讲解了三种常见的线程创建方式,但是相比较而言,Runnable接口实现要比继承Thread类具有很大的优势,如:

1.Runnable适合多个相同的程序代码的线程去处理同一个资源

2.可以避免Java中的单继承的限制

3.增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

         至于线程的启动,都是调用start()方法,需要特别注意的:我们不能对同一线程对象两次调用start()方法;
 以上就是关于多线程的基本介绍和三种创建方式,希望能帮助大家更好的去理解Java中的多线程,更高效地使用线程开发程序;

0 0
原创粉丝点击