一.线程与进程
一个程序就是一个进程,一个程序中的多个任务称为线程,同时也可以看做是一条执行路径,进程是表示资源分配的基本单位,而线程是进程中执行运算的最小单位,也是调度运行的基本单位。
举例:打开电脑任务管理器,会发现有多项程序正在执行,每个程序执行中又可能有N个子任务在同时运行,每一项任务都可以看作是一条线程。
线程的调度:分时调度、抢占式调度
分时调度:线程均分CPU的时间
抢占式调度:优先级高的线程拥有使用CPU的优先权,当所有的线程优先级都是一样时通过随机的方式决定给一个线程使用权。
二.同步与异步/并发与并行
同步:排队执行,效率低但是安全
异步:同时执行,效率高但是数据不安全
并发:指两个或多个事件在同一个时间段内发生
并行:指两个或多个事件在同一时刻发生(同时发生)
三.继承Thread类
MyThread myThread = new MyThread();
myThread.start();
public class MyThread extends Thread{
@Override
public void run() {
for (int i=0;i<10;i++){
System.out.println("锄禾日当午"+i);
System.out.println(Thread.currentThread().getName());
}
}
}
run方法就是线程要执行的任务方法 ,run里面的代码就是一条新的执行路径 。这个执行路径的触发方式,不是调用run方法,而是通过thread对象的start方法来启动任务 子线程调用的方法只在子线程执行。每个线程都拥有自己的栈空间,共用一份内存。
四.实现Runnable
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+":我是一只大老虎"+i);
System.out.println(Thread.currentThread().getName());
}
Runnable接口是线程辅助类,仅定义了一个方法run()方法
1. 实现Runnable接口
2. 重写run()方法
3. 创建Runnable实例
4. 创建Thread实例
5. 将Runnable实例放入Thread实例中,通过线程实例控制线程的行为(运行,停止),在运行时会调用Runnable接口中的run方法。
实现runnable与继承Thread相比有如下优势:
1.通过创建任务,然后给线程分配的方式来实现的多线程,更适合多个线程同时执行相同任务的情况
2.可以避免单继承所带来的局限性
3.任务与线程本身是分离的,提高程序的健壮性
4.后续学习的线程池技术,接受runable类型的任务,不接收Thread类型的线程
注意:Java中真正能创建新线程的只有Thread类对象
通过实现Runnable的方式,最终还是通过Thread类对象来创建线程
五.带返回值的线程Callable
Callable使用步骤
1. 编写类实现Callable接口 , 实现call方法
class XXX implements Callable<T> {
@Override
public <T> call() throws Exception {
return T;
}
}
2. 创建FutureTask对象 , 并传入第一步编写的Callable类对象
FutureTask<Integer> future = new FutureTask<>(callable);
3. 通过Thread,启动线程
new Thread(future).start();
Callable获取返回值
Callalble接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞。
Runnable 与 Callable的不同点
1.Runnable没有返回值;Callable可以返回执行结果
2.Callable接口的call()允许抛出异常;Runnable的run()不能抛出
Runnable 与 Callable的相同点
1.都是接口
2.都可以编写多线程程序
3.都采用Thread.start()启动线程
实例演示:
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
for (int i=0;i<10;i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
return 100;
}
}
public class Practice {
public static void main(String[] args) throws InterruptedException {
Callable<Integer> c = new MyCallable();
FutureTask<Integer> task = new FutureTask<>(c);
new Thread(task).start();
Integer j = task.get();//获取返回值,会挡住主线程,停在此处等子线程执行完毕
System.out.println("返回值为:"+j);
for (int i=0;i<10;i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}