概念
- 进程:进程指正在运行的程序
- 线程:线程是进程种的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程,一个进程是可以又多个线程的,这种应用程序就称为多线程。
- 总结:一个程序运行后至少有一个进程,一个进程中可以包含多个线程
多线程的创建方式(两种)
1、 继承Thread类(Thread类在java.lang包里)
步骤:
1. 定义一个类继承Thread
2. 重写run方法
3. 创建子类对象,也就是创建线程对象
4. 调用start方法,开启线程并让线程执行,同时还会告诉jvm去调用run方法
定义类并继承Thread
public class SubThread extends Thread{
public void run(){
for(int i=0; i<50; i++){
System.out.println("线程" + Thread.currentThread().getName() + " "+ i);
}
}
}
编写测试类
public class ThreadDemo{
SubThread st = new SubThread();
st.strat();
for(int i=0; i<50; i++){
System.out.println("线程" + Thread.currentThread().getName() + " "+ i);
}
}
一些解释
Thread.currentThread().getName() 获取当前线程的名字
st.strat() 之所以不直接调用run方法是因为线程对象调用run方法是不会开启线程的,仅仅是调用方法而已。而线程对象调用start则是开启线程,并让jvm在新开启的线程中运行run方法。
2、实现Runnable接口
步骤:
1. 定义类实现Runnable接口
2. 覆盖接口中的run方法
3. 创建Thread类对象
4. 将Runnable接口的子类对象作为参数传递给Thread类的构造函数
5. 调用Thread类的start方法开启线程
定义类并实现Runnable接口
public class MyRunnable implements Runnable{
public void run(){
for(int i=0; i<50; i++) {
System.out.println("线程" + Thread.currentThread().getName() + " "+ i);
}
}
}
编写测试类
public class ThreadDemo{
public static void main(String[] args){
MyRunnable runnable = new MyRunnable();
Thread th = new Thread(runnable);
th.start();
for(int i=0; i<50; i++) {
System.out.println("线程" + Thread.currentThread().getName() + " "+ i);
}
}
}
线程池
通常线程池都是通过线程池工厂创建,再调用线程池中的方法获取线程,再通过线程去执行方法
线程池工厂类Executors,有一个静态方法 newFixedThreadPool(int nThreads)是用来创建线程池的
这个静态方法的返回值是接口ExecutorService的实现类。参数是表示线程池里养几个线程。
1、Runnable接口使用线程池
- 线程池测试类
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TreadPoolDemo {
public static void main(String[] args) {
//创建线程池对象并指定线程数量
ExecutorService service = Executors.newFixedThreadPool(3);
//创建实现了Runnable接口的类的对象
PoolRunnable pr = new PoolRunnable();
//从线程池中获取对象,会自动调用pr对象的run方法
service.submit(pr);
service.submit(pr);
service.submit(pr);
//线程池里共有3个线程,这里提交了4个任务,是不会对程序造成影响的,因为这个多出来的任务是等到正在执行别的任务的线程,执行完以后,再过来执行它,所以线程池中有多少线程并没有多大影响
service.submit(pr);
//submit方法调用结束后,程序并不终止,因为线程池控制了线程的关闭。而线程池是将使用完的线程又归还到了线程池中。
//关闭线程池
//service.shutdown();
}
}
- Runnable接口的实现类
public class PoolRunnable implements Runnable{
public void run() {
System.out.println(Thread.currentThread().getName() + "正在执行程序");
}
}
2、Callable接口使用线程池
Callable接口比Runnable接口多了两个好处:有返回值,能抛异常。至于使用方法,和Runnable一样。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadPoolDemo {
public static void main(String[] args) throws Exception{
ExecutorService service =Executors.newFixedThreadPool(2);
PoolCallable pc = new PoolCallable();
//使用线程池的submit方法时,不会直接返回Callable实现类的返回值
//而是会返回Future接口的实现类,所以可以直接创建Future对象来接收
//使用Future对象的get()方法可以接收Callable实现类的call方法的返回值
Future<String> f = service.submit(pc);
String s = f.get();
System.out.println(s);
//service.shutdown();
}
}
- Callable接口的实现类
import java.util.concurrent.Callable;
public class PoolCallable implements Callable<String>{
public String call() throws Exception{
System.out.println(Thread.currentThread().getName());
return "good";
}
}