JAVA多线程(二)- 多线程的创建和执行

一、多线程的创建和执行

方法一:继承Thread类(Thread类是JDK提供的一个抽象类)

用法:

1)继承Thread类,重写run()方法。该run方法将作为线程执行体。

2)创建Thread子类的实例,即创建了一个线程对象。

注意,new了一个Thread实例后,仅仅只是创建了一个线程对象,与其他普通JAVA对象一样,JVM为该线程对象在堆中分配了内存,初始化了成员变量的值,此时该线程仅仅是堆中的一个对象,并没有启动执行。

3)调用线程对象的start方法来启动该线程。

调用start方法后,JVM会为其创建方法调用栈和程序计数器,此时线程处于就绪状态,在就绪队列中等待CPU的调度。

class Thread1 extends Thread {
    public void run() {
        for(int i=0; i<100000; i++) {
            System.out.println("Thread1 is running " + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class Thread1Test {
    public static void main(String[] args) {
        new Thread1().start();
    }
}

方法二:实现Runnable接口

1)定义Runnable接口的实现类,实现接口的run方法。run方法将作为线程的执行体。

2)将Runnable实现类的实例包装到Thread中,作为Thread的target,创建一个Thread的实例,即创建一个线程对象。

3)调用线程对象的start方法,即启动该线程。

class Thread2 implements Runnable {

    @Override
    public void run() {
        System.out.println("Thread2 is running");
    }
}
public class Thread2Test {
    public static void main(String[] args) {
        new Thread(new Thread2()).start();
    }
}

注:Thread2Test的main方法中,调用了Thread类的一个构造函数: (Thread类部分源码)

    /**
     * Allocates a new {@code Thread} object. This constructor has the same
     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
     * {@code (null, target, gname)}, where {@code gname} is a newly generated
     * name. Automatically generated names are of the form
     * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
     *
     * @param  target
     *         the object whose {@code run} method is invoked when this thread
     *         is started. If {@code null}, this classes {@code run} method does
     *         nothing.
     */
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

方法三:实现Callable接口

待补充

public class CallableTest implements Callable<String> {

    @Override
    public String call() throws Exception {
        return Thread.currentThread().getName();
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建一个FutureTask对象,它将执行给定的Callable对象
        FutureTask<String> futureTask = new FutureTask<>(new CallableTest());
        // 创建线程对象,并启动线程
        new Thread(futureTask).start();
        // 获取线程执行的返回值
        System.out.println(futureTask.get());
    }
}

二、多线程运行的规则

1)启动线程必须使用Thread类的start方法,这是Thread类中的一个本地方法,调用start方法后,JVM会以多线程的形式自动执行线程执行体(即run方法)。如果直接调用run方法,将变成串行执行。

2)同一个Thread对象的start方法只能调用一次;已经执行完的线程也不能再次start(线程的run方法执行完成后,线程会自动关闭,此时当然不能再启动了)。否则会触发IllegalThreadStateException异常。

下面代码中,会有一个子线程正常运行,对该线程对象再次start时将触发异常。

public class Thread1Test {
    public static void main(String[] args) {
        Thread1 thread1 = new Thread1();
        // 下面两行代码会触发运行时异常: IllegalThreadStateException
        thread1.start();
        thread1.start();
    }
}

可以创建多个线程对象,分别调用start方法,执行同样的方法体(run方法):

下面代码new了两个Thread2对象,因此可以分别调用其start方法。

public class Thread2Test {
    public static void main(String[] args) {
        new Thread(new Thread2()).start();
        new Thread(new Thread2()).start();
    }
}

3)线程无需关闭,只要其run方法执行结束,该线程会自动关闭,该线程的生命周期就结束了。

4)多个线程启动,其启动的先后顺序是随机的。

三、多种创建方式的区别

1)继承Thread类的方式,占用了一个继承的名额

2)Thread本身也是继承自Runnable接口,所以继承Thread类本质上也是实现了Runnable接口

3)Runnable启动时需要Thread类的支持,Runnable实现类没办法单独start,必须包装到Thread类中才行。

4)多个线程对象可以共用同一个target(Runnable对象),适合多个线程处理同一份资源的情况。

5)Runnable中更容易实现资源共享。Thread中必须用static变量才能实现变量共享。Runnable中通过普通的变量就可以达到共享。

建议使用实现Runnable接口的方式创建和启动线程

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值