初识JUC并发编程
1. 线程池
在线程模块的学习中,我们会频繁的创建,销毁以及使用使用量特别大的资源,比如并发情况下的线程,会对性能产生极大的影响,Java提供了线程池,即提前创建多个线程,放入线程池中,使用时直接获取,使用完后放回池中,
可以避免频繁的创建销毁,实现重复利用,提高内存资源的使用率。
使用线程池的好处
- 相关接口API:ExecutorService与Executors,线程池的工具类,用于创建并返回不同类型的线程池
- ExecutorService:真正的线程池接口,子类有ThreadPoolExecutor
1. Executors:用于创建并返回不同类型的线程池
2. void execute(Runnable command); 执行命令,没有返回值
3. void shutdowm(); 关闭连接池
- 减少了创建新线程的时间,提高了响应速度
- 重复利用线程池中的资源,降低资源消耗
- 同区域存储,便于线程管理
- 代码示例:
package senior;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//测试线程池
public class poolTest {
public static void main(String[] args) {
//1.创建服务,线程池(参数为线程池大小)
ExecutorService service = Executors.newFixedThreadPool(10);
//2.通过线程池执行自定义的线程对象(代理模式)
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//2.关闭连接
service.shutdown();
}
}
class MyThread implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
2. JUC
2.1 线程与进程(review)
- 进程:一个程序,QQ.exe,Java.exe等。
- 线程:正在运行的百度网盘中的一条正在下载的子任务;或者是你正在使用的word编辑器,写字录入和自动保存都是线程来实现。
- Java中默认有的线程(两个):main,GC。
- **继承Thread类,实现Runnable接口(静态代理),Callable接口(vital)。
- Java没有权限不能够开启线程,由本地(native)方法调用底层C++实现,Java运行于自己的虚拟机之上,因此无法直接操作硬件。
2.2 并发与并行
网上有一个非常通俗易懂的栗子:
你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。
你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。
- 并行:就类似于n(n>1)个车道,第n个和第n+1,第n++条车道上的车辆互不影响(多核CPU)。
- 并发:多个线程操作同一个资源,在单核CPU中实现多线程,怎样解决?–>天下武功唯快不破(快速交替)。
- 并发编程的本质:充分利用CPU的资源。
2.3 线程的状态(review)
- NEW(新生)
- RUNNABLE(运行)
- BLOCKED(阻塞)
- WAITING(等待,死等)
- TIMED_WAITING(超时等待)
- TERMINATED(终止)
2.4 wait(Object) and sleep(Thead)
- 1.类:两者来自不同类的不同方法
- 2.锁的释放:wait方法会释放锁,sleep方法不会释放锁(抱着锁睡着了)
- 3.适用范围:wait必须在同步代码块中使用,sleep无要求
- 4.异常捕获:都需要异常的捕获于处理
3. synchronized锁回顾(vital)
- synchronized锁基础实现(以后我们会大量的使用到lambda表达式)
- 代码示例
package com.cyl.demo01;
//基本的卖票
/***
* 企业中的开发,代码一定得降低耦合性
* 线程是一个单独的资源类,没有任何的附属操作
* 1.属性,方法
*/
public class SafeTicketDemo01 {
public static void main(String[] args) {
//并发,多线程同时操作一个资源类,将资源类丢入线程
Ticket ticket = new Ticket();
//@FunctionInterface 函数式接口
// jdk1.8之后使用lambda表达式简化书写:(parameter)->{code}
new Thread(()->{
for (int i = 0; i < 20; i++) {
ticket.sale();
}
},"a0").start();
new Thread(()->{
for (int i = 0; i < 20; i++) {
ticket.sale();
}
},"a1").start();
new Thread(()->{
for (int i = 0; i < 20; i++) {
ticket.sale();
}
},"a2").start();
}
}
//资源类
class Ticket{
// 1.属性,方法(OOP思想)
private int ticketNums = 20;
//卖票的方法
//synchronized本质:队列与锁
public synchronized void sale() {
if (ticketNums > 0) {
System.out.println(Thread.currentThread().getName()+
"卖出了"+(ticketNums--)+"张票,剩余"+ticketNums);
}
}
}