一、线程
1.普通方法调用和多线程
可以看出,普通方法调用一个run()方法,它会等这个方法执行完,再继续主线程的任务,有一个等待的过程,只有一个执行路径。
而多线程呢,是多条执行路径,主线程和子线程并行交替执行。
2.程序、进行、线程
在操作系统中,运行的程序就是进程,一个进程里可以有多个线程。比如,此刻你电脑上的游戏程序开始运行,变成一个进程,里面即有画面又有声音,这一个个属于线程。
程序——指令和数据的有序集合,是一个静态的概念
进程——程序的一个执行过程,是一个动态的概念,也是系统资源分配的单位,我们说,给某个进程给多少资源等等的。
线程——一个进程中包含若干个线程,至少有一个,真正执行的其实是线程,线程是CPU调度和执行的单位。
- 核心点——注意
1.线程是独立执行的路径,因为CPU同一时间只做一件事
2.在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程
3.main() 称之为主线程,为系统的入口,用于执行整个程序
4.在一个进程中,如果开辟了多个线程,线程的运行由调度器(CPU)安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的干预的
5.对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制
6.线程会带来额外的开销,如cpu调度时间,并发控制开销
7.每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
二、线程创建
1.继承Thread类
- 自定义线程类继承Thread类
- 重写run()方法,编写线程体
- 创建线程对象,调用start()方法启动线程
public class TestThread extends Thread {
public static void main(String[] args) {
TestThread thread = new TestThread();
thread.start();
System.out.println("main");
}
@Override
public void run() {
//线程体
for (int i = 0; i < 8; i++) {
System.out.println("线程执行了");
}
}
}
- 注意:线程不一定立即执行,看CPU调度
2.实现Runable接口
- 定义一个类实现runable接口
- 重写run()方法
- 创建线程对象,调用start方法启动线程
public class TestRunnable implements Runnable {
@Override
public void run() {
System.out.println("runnable线程");
}
public static void main(String[] args) {
TestRunnable runnable = new TestRunnable();
//创建代理类对象
Thread thread = new Thread(runable);
thread.start();
System.out.println("main线程");
}
}
- 实现runable接口这种方法避免了单继承的局限性,灵活方便,可以同一个对象被多个线程使用。
Threadmy thread = new Threadmy();
new Thread(thread,"1").start();
new Thread(thread,"2").start();
new Thread(thread,"3").start();
3.实现Callable接口
- 实现callable接口,需要返回值类型
- 重写call方法,需要抛出异常
- 创建目标对象
- 创建执行服务:
ExecutorService ser = Executors.newFixedThreadPool(1);
- 提交执行
Future<Boolean> result1 = ser.submit(t1);
- 获取结果
boolean r1 = result1.get()
- 关闭服务
ser.shutdownNow();
public class TestCallable implements Callable {
@Override
public Object call() throws Exception {
System.out.println("callable");
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建对象
TestCallable callable = new TestCallable();
//创建执行服务
ExecutorService service = Executors.newFixedThreadPool(1);
//提交执行
Future<Boolean> result = service.submit(callable);
//获取结果
Boolean re = result.get();
//关闭
service.shutdownNow();
System.out.println(re);
//FutureTask<Integer> future = new FutureTask<Integer>(new TestCallable());
//new Thread(future).start();
//Integer integer = future.get();
//System.out.println(integer);
}
}
4.静态代理模式
静态代理模式——目标对象和真实对象去实现同一个接口,代理对象要代理真实角色(需要有真实参数的传输)
好处——代理对象可以做真实对象做不了的事,真实对象专注做自己的事
- 实现静态模式三要素
1、真实角色(委托对象)
2、代理角色
3、共同实现的接口
- 对比以实现Runable接口的形式创建多线程,可以发现,代理角色Thread类不需要我们创建,我们只需要写委托对象,实现Runnable接口,把委托对象的引用传递给Thread,借助Thread对象来开启线程即可。
- 我们发现thread底层其实是实现了Runnable接口,而runable也实现了这个接口,这就是它们共同实现的接口,thread作为代理,runable作为委托人。
class Thread implements Runnable {
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives();
static {
registerNatives();
}
5、Lamda表达式
public class lambda3 {
public static void main(String[] args) {
//在对接口的引用时,采用的是实例化实现该接口的类
ILove love = new Love();
love.lambda(0);
//匿名内部类
love = new ILove() {
@Override
public void lambda(int a) {
System.out.println(a);
}
};
love.lambda(2);
//lambda表达式
love = (int a)->{
System.out.println(a);
};
love.lambda(3);
//简化1: 去掉括号
love = a -> {
System.out.println("a");
};
love.lambda(4);
//简化2:去掉花括号
love = a -> System.out.println("a");
love.lambda(5);
}
}
interface ILove{
void lambda(int a);
}
class Love implements ILove{
@Override
public void lambda(int a) {
System.out