Java线程创建和启动

Java使用Thread类表示线程,所有的线程对象都必须是Thread类或子类的实例。

继承Thread类创建线程类

步骤:

  1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体内就是线程需要完成的任务,称为方法体。
  2. 创建Thread子类的实例,就是创建线程对象。
  3. 调用线程对象的start()方法来启动该线程。
public class FirstThread extends Thread
{
    private int i ;
    // 重写run方法,run方法的方法体就是线程执行体
    public void run()
    {
        for ( ; i < 100 ; i++ )
        {
            // 当线程类继承Thread类时,直接使用this即可获取当前线程
            // Thread对象的getName()返回当前该线程的名字
            // 因此可以直接调用getName()方法返回当前线程的名
            System.out.println(getName() +  " " + i);
        }
    }
    ...........
                //创建、并启动第一条线程
                new FirstThread().start();              
                // 创建、并启动第二条线程
                new FirstThread().start();

当使用本方法创建线程时,可以直接使用this获取当前线程。

线程还有以下方法:
Thread.currentThread():currentThread()是Thread类的静态方法,该方法返回当前正在执行的线程对象。
getName():该方法是Thread类的实例方法,返回的是该方法的线程名字。
setName(String name):为线程设置名字。

多线程运行结果
红色的标记可以看出两个线程不是连续的,说明没有共享数据。所以使用此方法创建的线程类,多个线程之间无法共享线程类的实例变量

只有调用start()方法,系统才会把run()方法当成线程执行体。如果直接调用run()方法,系统把线程对象当成普通对象,且run()方法当成普通方法。

实现Runnable接口创建线程类

步骤:

  1. 定义Runnable接口的实现类,并重写该接口的run()方法。
  2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread的对象,此对象才是真正的线程对象。
  3. 调用线程对象的start()方法启动该线程。
public class SecondThread implements Runnable
{
    private int i ;
    // run方法同样是线程执行体
    public void run()
    {
        for ( ; i < 100 ; i++ )
        {
            // 当线程类实现Runnable接口时,
            // 如果想获取当前线程,只能用Thread.currentThread()方法。
            System.out.println(Thread.currentThread().getName()
                + "  " + i);
        }
    }

    .....
            {
                SecondThread st = new SecondThread();     
                // 通过new Thread(target , name)方法创建新线程
                new Thread(st , "新线程1").start();
                new Thread(st , "新线程2").start();
            }

实现Runnable接口获得当前线程对象,则必须使用Thread.currentThread()方法。
采用本方法,可以实现线程之间共享数据。
这里写图片描述

使用Callable和Future创建线程

此方法可以把任意方法包装成线程执行体,而不像前两种方法都需要把Thread类的run()方法包装成线程执行体。
Callable接口提供一个call()方法作为线程执行体,但是此方法有返回值,且可以抛出异常。
但是Callable接口不是Runnable的子接口,Callable对象无法直接作为Thread的target。于是使用FutureTask类的Future接口来代表Callable接口里的call()方法的返回值,且FutureTask类也实现了Runnable接口,所以就可以作为Thread类的target。

步骤:

  1. 创建Callable接口实现类,并实现call()方法,该call()方法有返回值,再创建Callable实现类的实例。从Java8开始,可以直接使用lambda表达式创建Callable对象。
  2. 使用FutureTask来包装Callable对象。该FutureTask对象封装该Callable对象的call()方法返回值。
  3. 使用FutureTask对象作为Thread对象的target创建并启动线程。
  4. 调用FutureTask对象的get()方法来获得子线程执行结束后返回值。
public class ThirdThread
{
    public static void main(String[] args)
    {
        // 创建Callable对象
        ThirdThread rt = new ThirdThread();
        // 先使用Lambda表达式创建Callable<Integer>对象
        // 使用FutureTask来包装Callable对象
        FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)() -> {
            int i = 0;
            for ( ; i < 100 ; i++ )
            {
                System.out.println(Thread.currentThread().getName()
                    + " 的循环变量i的值:" + i);
            }
            // call()方法可以有返回值
            return i;
        });
        for (int i = 0 ; i < 100 ; i++)
        {
            System.out.println(Thread.currentThread().getName()
                + " 的循环变量i的值:" + i);
            if (i == 20)
            {
                // 实质还是以Callable对象来创建、并启动线程
                new Thread(task , "有返回值的线程").start();
            }
        }
        try
        {
            // 获取线程返回值
            System.out.println("子线程的返回值:" + task.get());
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
    }
}

三种方法对比

实现Runnalbe接口与实现Callable接口方式基本相同,只是Callable接口可以有返回值,可以抛出异常,所以归为一类。
实现Runnale,Callable接口方法的优缺点:

优点:
1. 可以继承其他类。
2. 适合多个相同线程来处理同一份资源。

缺点:
访问当前线程,都需要使用Thread.currentThread()方法。

继承Thread类方法:

优点:
编写简单,访问当前线程,只需要使用this即可。

缺点:
无法继承其他类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值