线程:
进程:是一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。
线程: 又称轻量级进程,程序中的一个顺序控制流程,同时也是cpu的基本调度单位,进程由多个线程组成,彼此间完成不同的工作,交替执行,称为多线程
Java虚拟机是一个进程,当中默认包含主线程(main),可通过代码创建多个独立的线程,与main并发执行
进程与线程的关系:
- 进程是操作系统资源分配的基本单位,而线程是CPU的基本调度单位
- 一个程序运行后至少有一个进程
- 一个进程可以包含多个线程,但至少有一个线程
- 进程之间不能共享数据段地址,但同进程的线程间可以
线程的基本组成:
-
cup时间片:操作系统(os)会为每个线程分配执行时间
-
运行数据: 堆空间,存储线程需使用的对象,多个线程可以共享堆中的对象
栈空间,存储线程需使用的局部变量。每个线程都拥有独立的栈
-
线程的逻辑代码
一个栈帧结构代表一个方法,一个方法执行完毕后执行下一个
一。 继承了Thread类就是一个线程
public class TestThread {
public static void main(String[] args) {
MyThread02 myThread02 = new MyThread02();
myThread02.run(); // 普通的方法调用
myThread02.start(); // 开始线程
} //在执行到start这时,只通知线程准备开始, 创建线程第一种方式
//程序继续向下执行,等到线程拿到时间片后再执行 1. 继承Thread
} //详细参考下图 2. 覆盖run方法
class MyThread02 extends Thread{ 3.创建子类对象
4. 调用start方法
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
}
二。实现runnable接口 用的多,多个任务可以重用
①:
public class TestThread {
public static void main(String[] args) {
MyThread02 myThread02 = new MyThread02();
Thread thread = new Thread(myThread02,ThreaName);
// 创建线程 以实现类对象作为参数传递给线程
// ThreaName设置线程名,可通过Thread.currentThread().getName()获得线程的名,
// 若不设置,默认是Thread-n
thread.start();
} 创建线程第二种方式
} //Runnable只是个接口,不是线程,Thread才是线程 1. 实现runnable接口
class MyThread02 implements Runnable{ 2. 覆盖run方法
// Runnable可以看做是一个线程任务,把他交给线程运行 3. 创建实现类对象
@Override 4. 创建线程对象
public void run() { 5. 调用start方法
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
}
②:匿名内部类
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
});
三。实现Callable接口 与Runnable相似 后续学
线程中常见的方法:
sleep(long millis): 当前线程主动休眠millis毫秒 限期等待
yield(): 当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片 无限期等待
join():允许其他线程加入到当前线程中
高级多线程:
线程问题:线程是宝贵的内存资源,单个线程约占1MB,过多分配容易造成内存溢出,频繁的创建及销毁线程会增加虚拟机回收频率,资源开销,造成程序性能下降。
线程池:
线程容器,可设定线程分配的数量上限,将预先创建的线程对象存入池中,并重用线程池中的线程对象,避免频繁的创建和销毁。
创建线程:
ExecutorService es = Executors.newFixedThreadPool(10); //获得指定线程的数量的线程池
ExecutorService es = Executors.newCachedThreadPool(); //获得动态线程数量的线程池
ExecutorService:线程池接口,可通过submit(task)提交任务代码
Executors:工厂类,可以通过此类获得一个线程池
Executor:线程池的顶级接口
所在包 java.util.concurrent.*;
callable接口:与runnable接口相似,实现之后代表一个线程任务,具有泛型返回值,可以声明异常
Future接口:异步接受ExecutorService.submit()所返回的状态结果,当中包含了call()返回值
V get()以阻塞形式等待Future中的异步处理结果(call()的返回值)
public class Demo2 {
public static void main(String[] args) throws Exception {
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("开始计算");
int sum = 0;
for (int i = 0; i < 50; i++) {
sum += i;
}
return sum;
}
};
//把callable对象转换成 可执行线程任务
FutureTask<Integer> task = new FutureTask<Integer>(callable);
//创建,启动 线程
Thread thread = new Thread(task);
thread.start();
//获取结果,等待call执行完毕后返回
Integer sum = task.get();//get指的是获取call这个函数的返回值,而且在获取返回值的时候会自动阻塞(等待call执行完毕后返回)
System.out.println("结果是" + sum);
}
}