一.Java多线程常用方法和概念
1.进程,线程概念与优点
进程
- 进程是一个程序的实列
- 是资源分配的基本单位
线程
- 是进程的子单位
两者的区别
- 进程是独立的,而线程存在进程内部是进程子集
- 线程之间共享进程的内存空间
- 进程通信比较复杂,线程通信如使用共享内存
- 线程更轻量,上下文切换成本比进程低
2. 并行与并发的概念
并发
-
同一时刻,应对多个事情的能力
并行
-
串行,
-
并行是同一时间同手做多件事情的能力
什么是串行,并行,并发
通俗点说:
- 串行,两个程序,这两个程序必须要严格按顺序执行,一个程序执行完才能执行另一个,这是串行。
- 并行,也是两个程序,在之执行第一个程序的同时执行第二个程序,由于要同时所以需要两个CPU。
- 并发,执行第一个程序,执行到一半,然后执行第二个程序,不断的切换直到只想完,这是并发,一个CPU就可以。
- 上面的理解只是一部分情况,要是细扣的话有点片面
- 比如:单核CPU上面也可以并行执行多个进程,进程A设计逻辑器件组1,进程B设计逻辑器件组2(不涉及被占用的逻辑器件指令)完全可以同时执行。
3. 同步与异步
从调用角度来看
- 需要等待结果返回(有些没有返回结果的,则等待执行结束),才能继续运行是同步。
- 不需要等待结果返回,继续运行就是异步
从写代码角度看
- 使用异步主要是为了提高效率,其次特定场景(需要同时执行)需要。
4. 线程的状态
5 .查看进程线程的方法
### windows
-
任务管理器可以查看进程与线程,PID进程号
-
在cmd里 tasklist查看进程,taskkill杀死进程
### linux
-
ps -fe 查看所有进程
-
kill -9 进程号 杀死进程
-
top 列出进程,还有使用CPU百分比
-
top -H -p PID 查看进程中的线程(参数-H是显示线程,-p是进程号),可以自动更新
### Java
- jps 查看所有Java进程(jdk的命令)
- jstack PID 查看java进程的所有线程状态,很详细,是快照
- jconsole 查看进程中线程的运行情况,图形化界面
6 .Thread类的常用方法
7.什么是JUC?
JUC
二.变量与对象的并发访问
1.并发问题与解决办法
2.synchronized使用与线程安全的类
3.synchronized原理与优化
wati 和sleep区别
并发和并行?
辅助类
减少计数CountDownLatch,允许一个或多个线程等待直到在其他线程中执行的一组操作完成的 同步辅助。
方法
CountDownLatch countDownLatch=new CountDownLatch(7);//构造方法,初始容量为7
countDownLatch.await();//当前一个或多个线程等待到计数为0
countDownLatch.countDown();//减少计数
countDownLatch.getCount();//返回当前计数
例子,有六个同学,当六个同学陆续离开后,班长锁门?
//案例,等6个同学离开,锁门
public static void main(String args[]) throws InterruptedException {
CountDownLatch countDownLatch=new CountDownLatch(6);//初始容量为6
for(int i=0;i<6;++i)
{
new Thread(()->{
System.out.println("同学"+"离开");
countDownLatch.countDown();//计数减一
},"线程"+i).start();
}
countDownLatch.await();//等待计数为0
System.out.println("锁门");
}
同步辅助类循环栅栏CyclicBarrier,允许一组线程全部等待彼此达到共同屏障点的同步辅助。
方法
例子:集齐7课龙珠就可以召唤神龙?
计数信号量SemaphoreDemo
方法
例子 :6辆车停3个车位
线程池ThreadPool,
线程池概述
优势
主要特点
涉及类的关系,
创建线程的三种方式
/*
创建线程的三种方法
*/
//第一种 匿名内部类,继承Thread类,重写run()
Thread th1=new Thread(){
public void run()
{
System.out.println("线程创建的第一种方式!");
}
};
//开启线程,
th1.start();
//第二种,实现runnable接口
Thread th2=new Thread(()->{System.out.println("第二种创建线程的方式!");});
th2.start();
//第三种 实现callable接口
FutureTask<Integer> task=new FutureTask<>(()->{return 2;});
Thread th3=new Thread(task);
th3.start();
System.out.println(task.get());
线程池
一.线程池的概述
1.简单了解
线程池(Thread pool)是线程的一种使用模式。线程池维护着多个线程,等待线程监督管理者分配可执行的并发任务。
2.线程池工作
- 避免了线程创建和销毁的代价
- 控制线程的运行数量(最大连接数等),不仅充分利用内核,而且能防止过度调用。
3.线程池的特点或优势
- 降低资源的消耗,重复利用已经创建的线程。
- 提高响应速度,不需要等待线程创建直接执行。
- 提高线程的管理,管理线程的最大创建数量,线程过多创建占用系统资源和降低系统稳定性。
二.线程池的架构
三.线程池的使用方式
四.线程池的底层原来
五.线程池的参数
六.线程池的底层实现参数
七.自定义线程池
java 多线程高频面试题
1.并发,并行,串行的区别
串行:在时间上不能重叠,上一个任务没完成,下一任务必须等待。
并行:在同一时间,同时处理多个任务,在时间上是重叠的,两个任务在同一时刻互不干扰的执行
并发:在一段时间,同时处理多个任务,允许两个任务互相干扰,单核CPU下是不能并行的,可以并发
2.并发的特性
原子性:对于一组操作要么全执行,要么全不执行。保证原子性要用锁synchronized,lock
有序性:程序的执行要按代码的顺序执行,JVM中指令重排,程序执行顺序可能不是代码的顺序导致线程安全问题。解决通过volatile,和锁.
可见性:一个线程修改了共享变量的值,另一个线程可以看到。
3.对线程安全的理解
### Thread类常用方法
* currentThread(),当前正在执行的线程对象的引用
* start(),开始执行线程的方法,启动线程
* yield(),当前线程愿意让出处理器的占用,注意,虽然让出但是可能再次被处理器调用
* sleep():静态方法,让线程睡眠一段时间,睡眠代表的含义是我让出对cpu的使用权,在睡眠的一段时间不会被cpu调用(这样会引发一个问题,有锁怎么办?后面会提到)
* join(),使当前线程等待另一个线程执行完毕后在执行,内部调用的Object的wait()方法实现
*
## 详解Callable,Future与FutureTask
JDK提供了Callable接口与Future类,解决开启一个线程去执行一个任务,这个任务有一个返回值。
### Callable接口
部分源码
```
@FunctionalInterface
public interface Callable<V>{
V call() throws Exception;
}
```
简单使用Callable接口的Demo
```
//自定义类实现Callable接口
class Task implements Callable<Integer>{
@Override
public Integer call() throws Exception{
//模拟计算过程,耗费时间1秒,计算结果2
Thread.sleep(1000);
return 2;
}
//测试(也是对Callable的使用)
public static void main(String [] args)
{
ExecutorService executor=Executors.newCachedThreadPool();
Task task=new Task();
Future<Integer> res=executor.submit(task);
//如何得到返回结果
result.get();//结果为2
}
}
```
对上述代码的解释:
* Callable配合线程池工具ExecutorService来使用。
* 然后线程池工具ExecutorService的submit()方法来让Callable执行,返回Future
* 通过Future的get()方法得到结果
### Future接口
部分源码
```
```
简单Demo
```
```
代码详解
### FutureTask
部分源码
```
```
简单Demo
```
```
代码详解
疑问,为什么要有FutureTask?
FutureTask能确保在高并发环境下任务只执行一次。
😄
FutureTask的几个状态
## 线程组和线程优先级