一、多线程
1.1进程和线程
进程:进程就是操作系统中运行的每一个应用程序。例如:微信,QQ
线程:线程是进程中的每一个任务。
多线程:在一个进程中,可以同时执行多个线程。同时完成多个任务。
并发:同时发生。多个线程同时完成任务时。
我们编写的应用程序运行时,也是一个进程。在我们进程中也是有线程的。
第一个现车给称为主线程:main方法就是第一个线程。
1.2 CPU轮转时间片
内存是作用是什么?处理程序数据。
CPU是中央处理器。程序想要运行必须使用CPU。
一个CPU同一时间只能处理一个程序运行。
一个程序想要运行必须抢到CPU
1.3 Thread类
Thread是线程的父类
(1) 构造方法
public Thread()
public Thread(String name)
name 是线程的名称
public Thread(Runnable target)
(2) 常用方法
public synchronized void start()
线程启动方法。 启动与运行现在不在是相同的概念。
线程启动之后,表示当前这个线程对象可以被运行。
public void run()
线程运行方法。
1.4 使用Thread类创建自定义的线程类
创建Thread类的子类。重写run的方法。为这个方法编写具体任务代码
Thread子类:
public class Thread01 extends Thread{
@override
public void run(){
System.out.println("abc");
}
}
main方法:
public static void main(String[] args){
Thread thread = new Thread01();
thread.start();//启动
}
1.5 为什么要用多线程
示例代码:
public class Thread01 extends Thread{
@override
public void run(){
for(int i = 1;i <= 1000 ;i++){
System.out.println(i+":abc");
}
}
}
public static void main(String[] args) {
Thread thread = new Thread01();//创建了一个新的子线程。
thread.start();//启动子线程。
//thread.run();
for(int i = 1;i<=1000;i++) {
System.out.println(i+":000");
}
}
输出:
1:000
1:abc
2:abc
3:abc
2:000
4:abc
3:000
在main方法中调用了thread.start();就表示在主线程中开辟了一个新的子线程。
主线程与子线程是并列的关系。二个线程之间的执行要通过抢CPU。
1.6 使用Runnable接口创建线程任务
线程:线程是在进程中的每一个任务。
Runnable接口就表示的任务接口。
@FunctionalInterface
public interfaceRunnable{
public abstract void run();
}
编写Runnable接口的实现类。任务类
public class Runnbale02 implements Runnable{
@Override
public void run() {
for(int i = 1;i<=1000;i++) {
System.out.println(i+":000");
}
}
}
使用任务类来创建一个线程对象
将任务类交给线程对象进行加载。线程启动时就可以调用任务类的run方法。
public static void main(String[] args) {
//使用Runnable接口的实现类
Runnbale02 runnbale02 = new Runnbale02();
Thread thread02 = new Thread(runnbale02);
thread02.start();
}
1.7 使用Callable接口编写任务类
在JDK1.5加入的关于线程的新的类。
解决了Runnable接口的二个问题:
1 异常没有抛出。调用线程启动时类,不知道在线程执行过程中有没有出现异常。
2 run方法没有返回值。调用线程结束之后。没有数据返回。
编写Callable接口下的实现类。任务类
public class Callable03 implements Callable<String> {
@Override
public String call() throws Exception {
for(int i = 1;i<=1000;i++) {
System.out.println(i+":***");
}
return "任务Callable03执行完成!";
}
}
1.8 使用线程池执行Callable接口的任务
(1) 线程池
池:容器。
线程池是存放大量线程对象的容器。
一个线程对象(Thread t)可不可能加载多个任务(Runnable r,Callable c)?
多个任务以串行方式,以先后顺序的方式进行执行。有多个任务可以同时使用同一个线程对象。
线程池:就是一个存放了大量线程对象的容器。
当有任务需要执行时,从线程池中拿一个线程对象。任务执行完成之后。将线程对象还给线程池。
(2)线程池Executor接口
实际开发时使用Executor接口的子接口ExecutorService
Submit 方法称为注册任务方法。
public interface ExcecutorService extends Executor{
<T>Future<T> submit(Callable<T> task);
}
这是一个创建线程池对象的工具类。
通过这个类的静态方法来获得不同的线程池对象
public class Executors {
返回一个有固定大小的线程池容器对象
public static ExecutorService newFixedThreadPool(int nThreads);
返回只有一个线程对象的线程池对象
public static ExecutorService newSingleThreadExecutor()
返回一个可变化的线程池对象
public static ExecutorService newCachedThreadPool()
}
(3) 返回值Future接口
用来接收Callable任务执行完成之后的返回值。
public interface Future<V> {
获取返回值对象的方式
V get() throws InterruptedException, ExecutionException;
}
public static void main(String[] args) {
Callable03 callable03 = new Callable03();
ExecutorService service = Executors.newFixedThreadPool(5);
Future<String> future03 = service.submit(callable03);
try {
System.out.println(future03.get());
} catch (Exception e) {
e.printStackTrace();
} finally {
service.shutdown();
}
}