什么是线程:线程(Thread)是一个程序内部的一条程序流程
程序中如果只有一条执行流程,那这个程序就是单线程程序
多线程:多线程是指从软硬件上实现的多条执行流程的技术(多条线程由CPU负责执行调度)
一、多线程的创建
1.继承Thread类
2.实现Runnable接口
3.实现Callable接口
二、Thread的常用方法
三、线程安全、线程同步
线程安全问题出现的原因:存在多个线程在同时执行;同时访问一个共享资源;存在修改该共享资源。
线程同步:解决线程安全问题的方案;解决办法:让多个线程实现先后依次访问共享资源
常见方案:加锁——每次只允许一个程序加锁,加锁后才能加入访问,访问完毕后自动解锁,然后其他线程才能再加锁进来
1.同步代码块
public void drawMoney(double money) {
//先判断是谁来取钱
synchronized (this) {
String name = Thread.currentThread().getName();
//1.判断余额是否足够
if (this.money >= money){
System.out.println(name + "来取钱" + money + "成功");
this.money -= money;
System.out.println(name + "取钱后,账户余额:" + this.money);
}else {
System.out.println(name + "来取钱:余额不足");
}
}
2.同步方法
public synchronized void drawMoney(double money) {
//先判断是谁来取钱
String name = Thread.currentThread().getName();
//1.判断余额是否足够
if (this.money >= money){
System.out.println(name + "来取钱" + money + "成功");
this.money -= money;
System.out.println(name + "取钱后,账户余额:" + this.money);
}else {
System.out.println(name + "来取钱:余额不足");
}
}
同步代码块范围更小;同步方法锁范围更大
3.Lock锁
//创建一个锁对象
private final Lock lk = new ReentrantLock();
public void drawMoney(double money) {
//先判断是谁来取钱
String name = Thread.currentThread().getName();
try {
lk.lock();//加锁
//1.判断余额是否足够
if (this.money >= money){
System.out.println(name + "来取钱" + money + "成功");
this.money -= money;
System.out.println(name + "取钱后,账户余额:" + this.money);
}else {
System.out.println(name + "来取钱:余额不足");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lk.unlock();//解锁
}
}
四、线程池
1.如何创建线程池
//1.通过ThreadPoolExecutor创建一个线程池对象
/*
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
*/
ExecutorService pool = new ThreadPoolExecutor(3,5,8, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
2.线程池处理Runnable任务
public class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "-->输出666~");
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Runnable target = new MyRunnable();
//三个核心线程
pool.execute(target);//线程池会自动创建一个新线程,自动处理这个任务,自动执行
pool.execute(target);
pool.execute(target);
//四个在任务队列中
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
//到了创建临时线程的时机了
//两个临时线程
pool.execute(target);
pool.execute(target);
3.线程池处理Callable任务
//1.让这个类实现Callable接口
public class MyCallable implements Callable<String> {
private int n;
public MyCallable(int n) {
this.n = n;
}
//2.重写call方法
@Override
public String call() throws Exception {
//描述线程的任务,返回线程执行返回后的结果
//需求:求1~n的和返回
int sum = 0;
for (int i = 1; i <= n; i++) {
sum += i;
}
return Thread.currentThread().getName() + "线程求出了1~" + n + "的和是:" + sum;
}
}
ExecutorService pool = new ThreadPoolExecutor(3,5,8, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
Future<String> f1 = pool.submit(new MyCallable(100));
Future<String> f2 = pool.submit(new MyCallable(200));
Future<String> f3 = pool.submit(new MyCallable(300));
Future<String> f4 = pool.submit(new MyCallable(400));
System.out.println(f1.get());
System.out.println(f2.get());
System.out.println(f3.get());
System.out.println(f4.get());
4.Executors工具类实现线程池
五、并发、并行、生命周期