0
点赞
收藏
分享

微信扫一扫

Java基础-线程-线程创建

Java工程师知识树 / Java基础


线程的创建

java.lang.Thread的构造方法API

创建线程的方式最终都是通过调用下面代码来创建线程:

/**
 * group - 线程组。 如果null并且有一个安全管理器,该组由SecurityManager.getThreadGroup()确定 。 如果没有安全管理员或SecurityManager.getThreadGroup()返回null ,该组将设置为当前线程的线程组。 
 * target - 启动此线程时调用其run方法的对象。 如果null ,这个线程的run方法被调用。 
 * name - 新线程的名称 
 * stackSize - 新线程所需的堆栈大小,或为零表示此参数将被忽略。
 */
public Thread(ThreadGroup group, Runnable target, String name,
              long stackSize) {
    init(group, target, name, stackSize);
}

Runnable接口是否在构造方法中传入为区分,上述构造方法分成两类创建线程对象:

  • 继承java.lang.Thread类,通过子类重写run方法实现业务逻辑处理后创建子类线程对象。
  • 入参传入java.lang.Runnable接口,当然可以使用Thread内的Runnable target,也可以使用自定义的Runnable接口实例。

然后这样分析的话很容易理解,传统意义上的,线程的创建有两种方式:

  • 1.继承java.lang.Thread类;不推荐使用,OOP单继承局限性。
  • 2.实现java.lang.Runnable接口;推荐使用,避免OOP单继承局限性,灵活方面,适合于多个线程处理同一资源的情况,比如买票,取号等。

线程创建与执行步骤:

  • 1.实现接口java.lang.Runnable重写其run方法;

其实java.lang.Thread也是实现了java.lang.Runnable接口。子类使用继承java.lang.Thread类形式创建线程,子类也重写了run方法,如果不重写,没有新创建线程的实际意义。

  • 2.创建线程对象:继承Thread类通过创建子类对象,实现Runnable接口通过new Thread(runnable)创建线程对象。

  • 3.通过start()方法启动线程。

从设计模式上看,java.lang.Threadjava.lang.Runnable实际上是一种静态代理的实现方式。

方式一:继承java.lang.Thread类

继承Thread类的话,重写run方法,在run方法中定义需要执行的任务。

通过继承继承Thread类创建自己的线程 :

package com.thread.study;

public class Test {
    public static void main(String[] args)  {
        System.out.println("执行主线程名称:"+Thread.currentThread().getName());
        MyThread thread1 = new MyThread();
        thread1.start();
        MyThread thread2 = new MyThread();
        thread2.run();
    }
}
 
 
class MyThread extends Thread{

    @Override
    public void run() {
        System.out.println("当前执行的线程名:"+Thread.currentThread().getName());
    }
}

运行结果:

执行主线程名称:main
当前执行的线程名:main
当前执行的线程名:Thread-0

结论:

  • 通过run方法调用并不会创建新的线程,而是在主线程中直接运行run方法,跟普通的方法调用没有任何区别
  • 虽然thread1的start方法调用在thread2的run方法前面调用,但是先输出的是thread2的run方法调用的相关信息,说明新线程创建的过程不会阻塞主线程的后续执行

方式二:实现java.lang.Runnable接口

通过实现Runnable接口来实现必须重写其run方法,在run方法中定义需要执行的任务。

package com.thread.study;

public class TestRunnable {
    public static void main(String[] args)  {
        System.out.println("执行主线程名称:"+Thread.currentThread().getName());
        MyRunnable runnable = new MyRunnable();
        new Thread(runnable).start();
        new Thread(runnable,"张三").start();
        new Thread(runnable,"李四").start();
    }
}
 
 
class MyRunnable implements Runnable{

    @Override
    public void run() {
        System.out.println("当前执行的线程名:"+Thread.currentThread().getName());
    }
}

必须将Runnable作为Thread类的参数,然后通过Thread的start方法来创建一个新线程来执行该子任务。

扩展:JDK针对Thread与Runnable的API

java.lang.Thread

public class Thread implements Runnable

java.lang.Runnable

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
  • Runnable接口应由任何类实现,其实例将由线程执行。该类必须定义一个无参数的方法,称为run
  • Runnable接口旨在为希望在活动时执行代码的对象提供一个通用协议。

创建线程实现图片下载实例

package com.thread.study;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

public class TestDownLoadPictures {

    public static void main(String[] args) {

        PictureThread pictureThread = new PictureThread("https://upload-images.jianshu.io/upload_images/25399192-f67ba4ca2a436ef1.png","E:\\study\\resource\\1.png");
        PictureThread pictureThread2 = new PictureThread("https://upload-images.jianshu.io/upload_images/25399192-f67ba4ca2a436ef1.png","E:\\study\\resource\\2.png");
        PictureThread pictureThread3 = new PictureThread("https://upload-images.jianshu.io/upload_images/25399192-f67ba4ca2a436ef1.png","E:\\study\\resource\\3.png");

        new Thread(pictureThread,"1.百度").start();
        new Thread(pictureThread2,"2.新浪").start();
        new Thread(pictureThread3,"3.搜狗").start();
    }
}


class PictureThread implements Runnable {

    private String picUrl;
    private String fileName;

    public PictureThread(String picUrl, String fileName) {
        this.picUrl = picUrl;
        this.fileName = fileName;
    }

    @Override
    public void run() {
        try {
            FileUtils.copyURLToFile(new URL(picUrl), new File(fileName));
            System.out.println(Thread.currentThread().getName() + "执行" + picUrl + "的下载");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

执行结果:

3.搜狗执行https://upload-images.jianshu.io/upload_images/25399192-f67ba4ca2a436ef1.png的下载
1.百度执行https://upload-images.jianshu.io/upload_images/25399192-f67ba4ca2a436ef1.png的下载
2.新浪执行https://upload-images.jianshu.io/upload_images/25399192-f67ba4ca2a436ef1.png的下载

使用线程池方式—Callable接口

JDK关于Callable的API

JDK关于ExecutorService(线程池类)中submit(Callable<T> task)方法的API

使用步骤:

1.创建线程池对象 eg:ExecutorService service = Executors.newFixedThreadPool(2);
2.创建Callable接口子类对象 eg:class MyCreateCallable implements Callable
3.提交Callable接口子类对象 eg:Future<String> future = service.submit(myCreateCallable)
4.关闭线程池 eg:service.shutdown();

使用示例:

package com.thread.study;

import java.util.concurrent.*;

public class ThreadPoolDemo {
    public static void main(String[] args) {
        //创建线程池对象
        ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象
        //创建Callable对象
        MyCreateCallable myCreateCallable = new MyCreateCallable();

        Future<String> future = service.submit(myCreateCallable);
        //注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。将使用完的线程又归还到了线程池中
        try {
            System.out.println("使用Callable接口返回值:"+future.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

        MyCreateRunnable myCreateRunnable = new MyCreateRunnable();
        //使用获取个教练
        service.submit(myCreateRunnable);
        //注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。将使用完的线程又归还到了线程池中

        //关闭线程池
        service.shutdown();
    }
}

// Callable接口实现类,call方法可抛出异常、返回线程任务执行完毕后的结果
class MyCreateCallable implements Callable {
    @Override
    public String call() throws Exception {
        System.out.println("我要一个教练:call");
        Thread.sleep(2000);
        System.out.println("教练来了: " + Thread.currentThread().getName());
        System.out.println("教我游泳,交完后,教练回到了游泳池");
        return "我是通过Callable创建的";
    }
}

// Runnable接口实现类,无法返回执行结果
class MyCreateRunnable implements Runnable {

    @Override
    public void run() {
        System.out.println("我要一个教练:call");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("教练来了: " + Thread.currentThread().getName());
        System.out.println("教我游泳,交完后,教练回到了游泳池");
    }
}

执行结果:

我要一个教练:call
教练来了: pool-1-thread-1
教我游泳,交完后,教练回到了游泳池
使用Callable接口返回值:我是通过Callable创建的
我要一个教练:call
教练来了: pool-1-thread-2
教我游泳,交完后,教练回到了游泳池
举报

相关推荐

0 条评论