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();
}
}