一、多线程
1.什么是进程?
进程就是在操作系统中动态运行的静态代码。
2.什么是线程?
线程就是进程中的某一项具体功能的执行过程。
进程 | 线程 |
---|---|
依赖操作系统 | 依赖进程 |
进程与进程之间的数据交互很困难 | 线程与线程之间的数据交互很容易 |
3.什么是多线程?
多个不同的执行线索共同运行的情况就是多线程。运行时某一时刻只有一个线索运行,只是不同的执行线索快速的切换而已。
4.为什么使用多线程?
(1)使用多线程的目的就是为了提高程序的执行效率。
(2)解决并发问题。
5.并行和并发有什么区别?
并行:多个处理器或多核处理器同时处理多个任务。
并发:多个任务在同一个 CPU 核上,按细分的时间片轮流(交替)执行,从逻辑上来看那些任务是同时执行。
二、多线程的创建方式以及区别
(1)通过继承Thread类创建线程类
1.创建一个类,继承Thread类
2.重写run方法
3.将需要由线程执行的具体动作写入run方法
package com.wangxing.test1;
/**
* 1.创建一个类,继承Thread类
2.重写run方法
3.将需要由线程执行的具体动作写入run方法
* @author Administrator
*
*/
public class TestThread extends Thread{
@Override
public void run() {
//得到当前线程的名称
String name=Thread.currentThread().getName();
for(int i=1;i<=100;i++) {
System.out.println(name+"--i=="+i);
}
}
}
package com.wangxing.test1;
public class TestMain {
public static void main(String[] args) {
/**
* 启动线程的步骤
* 1.创建线程对象【继承Thread类的对象】
* 2.通过线程对象调用start方法启动线程
*/
TestThread tth1=new TestThread();
tth1.start();
TestThread tth2=new TestThread();
tth2.start();
}
}
(2)通过实现Runnable接口创建线程类
1.创建一个类,实现Runnable接口
2.重写run方法
3.将需要由线程执行的具体动作写入run方法
package com.wangxing.test1;
/**
* 1.创建一个类,实现Runnable接口
2.重写run方法
3.将需要由线程执行的具体动作写入run方法
* @author Administrator
*
*/
public class MyThread implements Runnable{
@Override
public void run() {
//得到当前线程的名称
String name=Thread.currentThread().getName();
for(int i=1;i<=100;i++) {
System.out.println(name+"--i=="+i);
}
}
}
package com.wangxing.test1;
public class TestMain {
public static void main(String[] args) {
/*
* 1.创建有线程类执行的目标对象【实现Runnable接口的java类对象】
* 2.创建线程对象【java.lang.Thread类的对象】
* public Thread(Runnable target)
* public Thread(Runnable target, String name)
* 3.调用start方法启动线程运行
*/
MyThread mth=new MyThread();
Thread th1=new Thread(mth);
th1.start();
Thread th2=new Thread(mth);
th2.start();
}
}
(3)通过Callable和Future接口创建线程
Callable接口:Runnable接口的增强版
Callable接口提供了一个call()方法作为线程执行体,但call()方法比run()方法功能更强大
1、call()方法可以有返回值;
2、call()方法可以声明抛出异常;
完全可以提供一个Callable对象作为Thread的target,而该线程的线程执行体就是call()方法。
问题是Callable对象不能直接作为Thread的target(Callable接口是JAVA新增的接口,而且它不是Runnable接口的子接口)
Future接口:代表Callable接口里call()方法的返回值,并为Future接口提供了一个FutureTask实现类,该类实现了Future接口,并实现了Runnable接口,所以FutureTask可以作为Thread类的target,同时也解决了Callable对象不能作为Thread类的target这一问题。
Future接口的几个公共方法来控制与它关联的Callable任务:
1、boolean cancel(boolean mayInterruptIfRunning):试图取消Future里关联的Callable任务;
2、V get():返回Callable任务里call()方法的返回值,调用该方法将导致程序阻塞,必须等到子线程结束以后才会得到返回值;
3、V get(long timeout, TimeUnit unit):返回Callable任务里call()方法的返回值。该方法让程序最多阻塞timeout和unit指定的时间,如果经过指定时间后,Callable任务依然没有返回值,将会抛出TimeoutException异常;
4、boolean isCancelled():如果Callable任务正常完成前被取消,则返回true;
5、boolean isDone():如果Callable任务已经完成, 则返回true;
步骤:
1、创建Callable接口实现类,并实现call()方法,该方法将作为线程执行体,且该方法有返回值,再创建Callable实现类的实例;
2、使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值;
3、使用FutureTask对象作为Thread对象的target创建并启动新线程;
4、调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
package com.wangxing.test1;
import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int i=1;
//得到当前线程的名称
String name=Thread.currentThread().getName();
for(;i<=100;i++) {
System.out.println(name+"--i=="+i);
}
return i;
}
}
package com.wangxing.test1;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class TestMain {
public static void main(String[] args) {
//目标对象
MyCallable mycall=new MyCallable();
//目标对象的封装
FutureTask<Integer> task1=new FutureTask(mycall);
//线程对象
Thread th1=new Thread(task1);
//启动线程
th1.start();
try {
//是否取消正在执行的线程任务
task1.cancel(true);
//判断是否是线程任务没有运行结束之前取消线程认为
if(task1.isCancelled()) {
System.out.println("关闭窗口!");
}
//判断线程任务是否正常执行完毕
if(task1.isDone()) {
//得到线程任务的执行结果
int task_Thread_1=task1.get();
System.out.println("线程1的运行结果--"+task_Thread_1);
}else {
}
} catch (Exception e) {
e.printStackTrace();
}
FutureTask<Integer> task2=new FutureTask(mycall);
Thread th2=new Thread(task2);
th2.start();
try {
int task_Thread_2=task2.get();
System.out.println("线程2的运行结果--"+task_Thread_2);
} catch (Exception e) {
e.printStackTrace();
}
}
}