目录
多线程的创建方式三:实现Callable接口、FutureTask类
多线程
线程Thread是一个程序内部的一条执行流程
多线程的创建方式一:继承Thread类
编码简单,但线程类已继承Thread,无法继承其他类,不利于功能扩展
注意:
1.启动线程需调用start方法(多线程,向CPU注册该线程),而不是run方法(只是普通方法调用,仍是单线程)
2.主线程的任务不要放在子线程之前
多线程的创建方式二:实现Runnable接口
详细实现:
优点是任务类只是实现接口,还可以继续继承其他类,实现其他接口,扩展性强
缺点是多了一个runnable对象
匿名内部类写法
多线程的创建方式三:实现Callable接口、FutureTask类
前两种线程创建方式,重写的run方法均不能直接返回结果
优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;可以在线程执行完毕后去获取线程执行的结果
缺点:编码复杂一点。
Thread常用方法
在线程start前给它取名字哈,或者创建的时候就起名哈
线程安全
多个线程在同时操作同一个共享资源时,可能会出现业务安全问题
就是操作系统里学的线程那块,什么读者写者、哲学家就餐什么的
方法一:同步代码块
ctrl + alt +t 9synchronized
锁是“黑马”,实际上换成什么都行,但也会有一个问题,那就是所有人都用一把锁,实际上可能取钱操作只需要按账户锁
所以应该用this作为锁
synchronized(this){}
this刚好代表共享资源
静态方法用类名.class作为锁
方法二:同步方法
同步代码块锁的范围小一点,性能更好,同步方法锁的范围更大,性能差一些[这点性能差距现在几乎可以忽略了]
同步方法可读性更好
方法三:Lock锁
可以创建出锁对象,进行加锁解锁,更灵活方便强大
Lock是接口,不能直接实例化,可以采用它的实现类ReentrantLock
比如每个账户都需要一个锁,所以应该把锁放在创建账户对象里
1.建议用final修饰
2.保证中间出问题,也要能解锁,所以用try-catch-finally,finally解锁
线程通信
生产者消费者haha
上述方法应该使用当前同步锁对象进行调用。
线程池
线程池就是一个可以复用线程的技术。
用户每发起一个请求,后台就需要创建一个新线程来处理,新任务来了又要创建新线程处理的,而建新线程的开销是很大的,并且请求过多时,肯定会产生大量的线程出来,这样会严重影响系统的性能。
工作线程WorkThread和任务队列WorkQueue,控制线程数量,复用线程处理任务;同时也控制任务数量,避免系统资源耗尽
任务其实是对象,必须实现了Runnable或Callable接口
创建线程池
接口ExecutorService,用它的实现类ThreadPoolExecutor
使用ThreadPoolExecutor
线程池的注意事项
1、临时线程什么时候创建?
新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程。
2、什么时候会开始拒绝新任务?
核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始拒绝任务。
线程池处理Runnable任务
拒绝策略
线程池处理Callable任务
Executors工具类实现线程池(白雪
是一个线程池的工具类,提供了很多静态方法用于返回不同特点的线程池对象。
注意 :这些方法的底层,都是通过线程池的实现类ThreadPoolExecutor创建的线程池对象
计算密集型的任务:核心线程数量=CPU的核数+1
IO密集型的任务:核心线程数量=CPU核数*2
大型并发系统环境中使用Executors如果不注意可能会出现系统风险
并发、并行(多线程是并发和并行同时进行的
正在运行的程序(软件)就是一个独立的进程。
线程是属于进程的,一个进程中可以同时运行很多个线程。
进程中的多个线程其实是并发和并行执行的。
并发的含义
进程中的线程是由CPU负责调度执行的,但CPU能同时处理线程的数量有限,为了保证全部线程都能往前执行CPU会轮询为系统的每个线程服务,由于CPU切换的速度很快,给我们的感觉这些线程在同时执行,这就是并发。
并行的理解
在同一个时刻上,同时有多个线程在被CPU调度执行。
线程的生命周期
悲观锁 乐观锁
什么是悲观锁,乐观锁,举例和适用场景,悲观锁实现_乐观锁和悲观锁的应用场景,怎么实现-CSDN博客
Demo.java
package cn.ptz.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Demo1 {
public static void main(String[] args) throws Exception {
// two people give out the gifts(100
List<String> gift = new ArrayList<>();
String[] names = {"1gift","2gift","3gift","4gift","5gift","6gift"};
Random r = new Random();
for (int i = 0; i < 100; i++) {
gift.add(names[r.nextInt(names.length)] + (i + 1));
}
System.out.println(gift);
// 线程类 -> 线程对象
SendThread a = new SendThread(gift,"aa");
a.start();
SendThread b = new SendThread(gift,"bb");
b.start();
a.join(); // 等待线程结束
b.join();
System.out.println(a.getCount());
System.out.println(b.getCount());
}
}
SendThread.java
package cn.ptz.thread;
import java.util.List;
import java.util.Random;
public class SendThread extends Thread {
private List<String> gift;
private int count;
public SendThread(List<String> gift, String name) {
super(name);
this.gift = gift;
}
@Override
public void run() {
Random r = new Random();
String name = Thread.currentThread().getName();
// 发礼物
// 线程安全
// synchronized (this){} 这个锁不合适,因为两个线程的this不一样,没锁住
while (true) {
synchronized (gift){
if (gift.size() < 10){
break;
}
String rs = gift.remove(r.nextInt(gift.size()));
System.out.println(name + ":" + rs);
count++;
}
}
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}