Thread类

1 创建和启动一个线程

  • 创建Thread子类对象;
  • 子类对象调用方法start(),让线程程序执行,JVM调用线程中的run;

1.1 为何要继承Thread类,并调用它的start方法才能开启线程呢?

  • 继承Thread类,因为它用来描述线程,具备线程应该有的功能。

1.2 为什么不直接创建Thread类呢?

Thread t1=new Thread();
t1.start();

这样做没有错,但是该start调用的是Thread类中的run方法,而这个run方法没有做什么事情,更重要的是这个run方法中并没有定义我们需要让线程执行的代码。

1.3 创建线程的目的是什么?

是为了建立程序单独的执行路径,让多部分代码实现同时执行。
自定义线程需要执行的任务都定义在 run 方法中。Thread 类run方法中的任务并不是我们需要的,只有重写这个run方法。既然Thread类已经定义了线程任务的编写位置(run方法),那么只要在编写位置(run方法)中定义任务代码即可。所以重写了run方法动作。

2 获取线程名字Thread类方法currentThread

  • JVM开启主线程,运行方法main,主线程也是线程,是线程必然就是Thread类对象;
  • Thread类中static Thread currentThread(),返回正在执行的线程对象;

2.1 设置线程名字

public class NameThread extends Thread{
    public void run(){
        System.out.println(super.getName());
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        NameThread nt = new NameThread();
        nt.setName("子线程");
        nt.start();

        Thread t = Thread.currentThread();
        System.out.println(t.getName());

    }
}

3 Thread类方法sleep

public class SleepThread extends Thread{
    public void run(){
        for (int i = 0; i < 5; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(i);
        }
    }
}
public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {
       new SleepThread().start();
    }
}

4 实现线程的另一种方式,实现Runnable接口

public class SubRunnable implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println("run..."+i);
        }
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        SubRunnable sr=new SubRunnable();
        Thread t=new Thread(sr);
        t.start();
    }

}

4.1 实现Runnable的原理

继承Thread类和实现Runnable接口有什么区别呢?

  • 实现Runnable接口,避免了继承Thread类的单继承局限性。覆盖Runnable接口中的run方法,将线程任务代码定义到run方法中;
  • 只有创建Thread类的对象才可以创建线程。线程任务被封装到Runnable接口的run方法中,而这个run方法属于Runnable接口的子类对象,所以将这个子类对象作为参数传递给Thread的构造函数。这样线程对象创建时就可以明确要运行的线程的任务。

4.2 实现Runnable的好处

避免了单继承的局限性,较为常用。更加符合面向对象,线程分为2部分,一部分线程对象,一部分线程任务。如果继承Thread类,线程对象和线程任务耦合在一起。一旦创建Thread类子类对象,既是线程对象,又有线程任务。实现Runnable接口,将线程任务担负分离出来封装成对象,类型就是Runnable接口类型。Runnable接口对线程对象和线程任务进行解耦。

5 匿名内部类实现线程

  • 前提:继承或者接口实现;
new 父类或者接口(){
   重写抽象方法
}
public class ThreadDemo {
    public static void main(String[] args) {
        //继承方式  XXX extends Thread{public void run(){}}
        new Thread(){
            public void run(){
                System.out.println("++=");
            }
        }.start();

        //实现接口方式   XXX implements Runnable{public void run()}
       Runnable r=  new Runnable(){
            public void run(){
                System.out.println("$$$$");
            }
        };
       new Thread(r).start();
    }
}

6 线程的状态图

  • 受阻塞:线程具有CPU的执行资格,等CPU的资源;
  • 休眠等待:线程放弃CPU的执行资格;
    这里写图片描述

7 线程池

其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。

7.1 使用线程池方式—Runnable接口

通常,线程池都是通过线程池工厂创建,再调用线程池中的方法获取线程,再通过线程去执行任务方法。
- Executors:线程池创建工厂类;public static ExecutorService newFixedThreadPool(int nThread),返回线程池对象;

public class ThreadPoolRunnable implements Runnable {
    public void run(){
        System.out.println(Thread.currentThread().getName()+"线程提交的任务");
    }
}
public class ThreadPoolDemo {
    public static void main(String[] args) {
        ExecutorService es = Executors.newFixedThreadPool(2);
        es.submit(new ThreadPoolRunnable());
        es.submit(new ThreadPoolRunnable());


    }
}

8 实现线程的第3中方式,实现Callable 接口方式

实现步骤:
1. 工厂类Executors 静态方法newFixedThreadPool 方法创建线程池对象;
2. 线程池对象ExecutorService 接口实现类,调用方法submit 提交线程任务;submit(Callable c)

public class ThreadPoolCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "test pool";
    }
}
public class ThreadPoolDemo1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService es = Executors.newFixedThreadPool(2);
        //返回Future接口的实现类
        Future<String> f = es.submit(new ThreadPoolCallable());
        String s=f.get();
        System.out.println(s);
    }

}

9 使用多线程求和

public class GetSumCallable implements Callable<Integer> {

    private int a;

    public GetSumCallable(int a) {
        this.a = a;
    }

    public Integer call() {
        int sum=0;
        for (int i = 0; i <= a; i++) {
            sum += i;
        }
        return sum;
    }
}

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * 求和不能用Runnable,它没有返回值
 */
public class ThreadPoolDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<Integer> f1 = es.submit(new GetSumCallable(100));
        Future<Integer> f2 = es.submit(new GetSumCallable(200));

        System.out.println(f1.get());
        System.out.println(f2.get());

        es.shutdown();

    }
}

猜你喜欢

转载自blog.csdn.net/u012292754/article/details/79926809