多线程

自作多情 提交于 2020-04-05 18:10:08

进程vs线程:

进程:每个程序被运行加载到内存之后,都会被操作系统作为一个进程,进程是处于运行过程中的程序,是具有独立功能,被操作系统进行资源分配和调度的独立单元。

线程:一个进程里面可以拥有多个线程,线程拥有自己的堆栈,程序计数器和自己的局部变量,但是不拥有系统资源,多个线程共享进程的系统资源。

创建线程的三种方式:

1.继承Thread类创建线程类

继承Thread类,重写run()方法,该run()方法就代表程序需要完成的任务。创建Thread子类的实例,即创建线程对象。然后通过start()方法启动线程。

 1 public class MyThread extends Thread {
 2     private int count;
 3 
 4     @Override
 5     public void run() {
 6 
 7         for (; count < 100; count ++) {
 8             System.out.println(getName() + "---" + count);
 9         }
10     }
11 
12     public static void main(String[] args) {
13         for (int i = 0; i < 100; i++) {
14             System.out.println(Thread.currentThread().getName() + i);
15             if (i == 20) {
16                 new MyThread().start();
17                 new MyThread().start();
18             }
19         }
20     }
21 }

2.实现Runnable接口来创建并启动多线程

继承Runnable接口,并重写该接口的run()方法。创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread类对象,该Thread类对象才是真正的多线程对象。然后调用start()方法来执行该Thread实例线程。

示例:

 1 public class MyRunableThread implements Runnable {
 2 
 3     private int count = 0;
 4 
 5     @Override
 6     public void run() {
 7         for (; count < 20; count ++){
 8             System.out.println(Thread.currentThread().getName() + "--" + count);
 9         }
10     }
11 
12     public static void main(String[] args){
13         for (int i=0; i<30; i++){
14             System.out.println(Thread.currentThread().getName() + "--" + i);
15             if (i == 20){
16                 MyRunableThread myRunableThread = new MyRunableThread();
17                 new Thread(myRunableThread, "子线程1").start();
18                 new Thread(myRunableThread, "子线程2").start();
19             }
20         }
21     }
22 }

  3.使用Callable和Future创建线程

Java无法将任意方法包装成线程执行体,在Java5之后提供了一个Callable接口,该接口提供了call()方法作为线程执行体,类似于Runnable接口,call()方法类似于run()方法。但是call()方法比run()方法作为执行体,就更加强大。

1.call()可以有返回值。

2.call()可以声明抛出异常。

public class MyCallableThread {

    public static void main(String[] args) {
        //FutureTask包装Callable实例对象,此处使用了Lambda表达式来创建一个Callable对象
        FutureTask<Integer> task = new FutureTask<>(() -> {
            int count = 0;
            for (; count < 10; count++) {
                System.out.println(Thread.currentThread().getName() + "--" + count);
            }
            return count;
        });

        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "--" + i);
            if (i == 20) {
                new Thread(task, "callAbleThread").start();
            }
        }
        try {
            //Callable线程获取返回值
            System.out.println("线程的返回值为:" + task.get());
        } catch (Exception e) {
            e.getStackTrace();
        }
    }
}

 Future接口代表Callable接口里call()方法的返回值,FutureTask是Future接口的实现类,FutureTask实现类实现了Future接口和Runnable接口,可以做为Thread类的Target。Future接口里提供了如下几个方法来控制实现Callable接口的任务:

boolean cancel(Boolean mayInterruptIfRunning) 试图取消该Future里关联的Callable任务。

V get()返回Callable任务里的返回值。该方法会阻塞程序,必须等子线程结束后,才会得到返回值。

V get(long timeOut, TimeUnit unit)返回Callable任务里的返回值。该方法让程序最多阻塞的最长时间,由timeOut和unit来指定,如果超时,Callable接口依然没有返回值,则会抛出TimeOutException异常。

boolean isCancelled()如果在Callable任务正常执行前被取消,则返回true

boolean isDone()如果Callable任务已经完成,则返回true。

Callable接口创建线程的步骤:

1)创建Callable接口的实现类,并实现Call()方法,该方法作为线程的执行体,且该Call()方法有返回值,在创建Callable实现类的实例。也可以使用Lambda表达式来创建Callable接口的实例。

2)使用FutureTask对象来包装Callable接口的实现类实例,FutureTask包装了Callable实现类的返回值。

3)使用FutureTask对象作为Thread对象的target创建并启动多线程。

4)调用FutureTask对象的get()方法来获取子线程执行结束后的返回值。

 

控制线程

(1)join线程

join()方法时Thread提供一个线程等待另外一个线程完成的方法。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!