一、设计模式:
java一共有23中设计模式
二、多线程高并发
熟练掌握api,能够完成并发编程
熟读api源码,掌握其原理
理解java虚拟机内存模型
操作系统对并发的支持
为什么要学习并发编程:
几乎任何一个应用都是并发的多线程的
并发的优点
发挥多核处理器的强大的能力
建模的简单性
异步事件的简化处理
响应更加灵敏的用户界面
1.找工作
2.了解了并发编程,提高代码的编写能力
3.解决工作中遇到的高并发问题
并发的缺点
安全性问题
活越性问题(多个线程是在抢占cpu,秩序混乱,(饥恶状态)(死锁))
性能问题(多线程并不一定快)
线程安全性问题
创建线程的 多种方式
多线程运行 卖票
线程安全性问题
提出解决方案 synchronized
解决线程安全性问题
synchronized原理
。。。
什么是并发?
java代码最终被翻译成字节码,java虚拟机执行的是字节码指令,最终运行在cpu上
并发是多个线程在一块执行
什么是多线程?
每一个线程就是一个顺序执行流
多线程并不一定是并发
1
int a=10;
2
int b=20;
3
int c=a+b;
4
System.out.println()
5
Java虚拟机从上往下顺序执行(java虚拟机中的寄存器)
6
垃圾收集器(gc),在后台工作(令一个线程在执行)
7
java虚拟机内存有两个区域
8
一个是被线程所供享的(堆和方法区)
9
一个是被线程所独占的(私有线程存储区)
10
什么是进程?
一个运行中的程序
进程是资源分配的基本的单位
进程中包含着多个线程,线程共享进程的资源
线程是处理器电镀的基本单位。(线程是轻量级的线程,进程在进行切换的时候会浪费更多的资源)
线程一定会快吗?
迅雷多线程下载为什么快
并不是多线程性能提高了
而是由于下载接口多了,最后进行了合并
使得整体的完成时间减少了。
垃圾收集:!!!有空看看。
线程的状态
初始化(start())=》就绪态=》运行态=》终止态(Dead())
image.png
1
//先演示下线程之间的状态。
2
public class NewThread implements Runnable{
3
@Override
4
public synchronized void run() {
5
while (true){
6
// System.out.println("自定义的线程运行了");
7
try {
8
wait();//等待
9
// Thread.sleep(100);
10
} catch (InterruptedException e) {
11
e.printStackTrace();
12
}
13
System.out.println("自定义的线程运行了");
14
}
15
16
17
}
18
19
public static void main(String[] args) {
20
21
NewThread n = new NewThread();
22
//初始化状态
23
Thread thread=new Thread(n);//创建了线程,并指定了线程方法
24
25
thread.start();//启动线程
26
while(true){
27
synchronized (n){
28
System.out.println("主线程执行了");
29
try {
30
Thread.sleep(100);
31
} catch (InterruptedException e) {
32
e.printStackTrace();
33
}
34
n.notifyAll();//唤醒
35
}
36
37
}
38
}
39
40
41
}
42
创建线程的多种方式:
继承thread
ThreadGroup 线程组(对线程进行分组)
stackSzie 栈大小(虚拟机课用的)
interrupted() 中断线程
isinterrupted ()判断是否中断
1
2
//继承Thread创建线程实现多线程
3
public class Demo1 extends Thread {
4
5
public Demo1(String name) {
6
super(name);
7
}
8
9
10
11
public void run() {
12
while (!interrupted()){//不可以true
13
System.out.println(getName() + "线程执行了");
14
try {
15
Thread.sleep(200);
16
} catch (InterruptedException e) {
17
e.printStackTrace();
18
}
19
}
20
21
}
22
23
24
public static void main(String[] args) {
25
Demo1 d1=new Demo1("线程1");
26
Demo1 d2 =new Demo1("线程2");
27
28
// d1.setDaemon(true);//守护线程,支持性线程
29
// d2.setDaemon(true);//守护线程,支持性线程
30
31
d1.start();
32
d2.start();
33
34
d1.interrupt();//中断
35
// try {
36
// Thread.sleep(2000);//休息两秒钟
37
// } catch (InterruptedException e) {
38
// e.printStackTrace();
39
// }
40
}
41
}
42
实现Runnable接口
1
//实现Runnable接口实现线程的创建
2
public class Demo2 implements Runnable{
3
@Override
4
public void run() {
5
while (true){
6
System.out.println("thread running...");
7
}
8
}
9
10
public static void main(String[] args) {
11
12
Thread thread=new Thread(new Demo2());
13
thread.start();
14
}
15
16
}
匿名内部类的方式
1
//匿名内部类两种方式
2
public class Demo3 {
3
public static void main(String[] args) {
4
//继承thread子类实现
5
// new Thread(){
6
// public void run(){
7
// System.out.println("thread start..");
8
// }
9
// }.start();
10
11
//将线程任务作为参数传进去
12
// new Thread(new Runnable() {
13
// @Override
14
// public void run() {
15
// System.out.println("thread start..");
16
// }
17
// }).start();
18
19
20
21
22
new Thread(new Runnable() {
23
@Override
24
public void run() {
25
System.out.println("runnable");
26
}
27
}){
28
public void run(){
29
System.out.println("sub");
30
};
31
}.start();
32
}
33
}
34
带返回值的线程
1
import java.util.concurrent.Callable;
2
3
import java.util.concurrent.FutureTask;
4
//带返回值的线程
5
public class Demo4 implements Callable {
6
7
8
public static void main(String[] args) throws Exception{
9
Demo4 d4=new Demo4();
10
FutureTask taks =new FutureTask<>(d4);
11
Thread t=new Thread(taks);
12
t.start();
13
14
System.out.println("我先干点别的。。");
15
16
Integer result=taks.get();
17
18
System.out.println("线程执行的结果为:"+result);
19
}
20
21
@Override
22
public Object call() throws Exception {
23
System.out.println("正在进行紧张的计算。。。");
24
Thread.sleep(3000);
25
return 1;
26
}
27
}
定时器(quartz)
1
2
import java.util.Timer;
3
import java.util.TimerTask;
4
//定时器
5
public class Demo5 {
6
public static void main(String[] args){
7
Timer timer=new Timer();
8
//设置每隔多长时间执行,这个里面有很多方法。
9
timer.schedule(new TimerTask() {
10
@Override
11
public void run() {
12
System.out.println("timer task is run");
13
}
14
},0,1000);
15
}
16
}
应用场景
线程池的实现
1
2
import java.util.concurrent.Executor;
3
import java.util.concurrent.ExecutorService;
4
import java.util.concurrent.Executors;
5
6
//创建了一个池子,里面放的都是线程,用到了线程就从这个里面拿,用完进行回收,有空间换时间。
7
public class Demo6 {
8
public static void main(String[] args) {
9
// ExecutorService threadPool = Executors.newFixedThreadPool(10);
10
ExecutorService threadPool = Executors.newCachedThreadPool();
11
for (int i = 0; i < 1000; i++) {
12
13
14
threadPool.execute(new Runnable() {
15
@Override
16
public void run() {
17
System.out.println(Thread.currentThread().getName());
18
}
19
});
20
}
21
threadPool.shutdown();
22
}
23
Lambda表达式
函数式开发
更简洁
实现起来更方便
写出的代码性能更高
更支持高并发
1
2
import java.lang.reflect.Array;
3
import java.util.Arrays;
4
import java.util.List;
5
//lambda表达式并行处理集合
6
public class Demo7 {
7
public static void main(String[] args) {
8
List values= Arrays.asList(10,20,30,40);
9
int res=new Demo7().add(values);
10
System.out.println("计算结果为:"+res);
11
}
12
13
public int add(List values){
14
// values.parallelStream().forEachOrdered(System.out::println);
15
// return 0;
16
//jdk可以弱化类型
17
//paralleStream //mapToInt
18
return values.parallelStream().mapToInt(a->a).sum();
19
}
20
}
21
spring实现多线程
Config.java
1
import org.springframework.context.annotation.ComponentScan;
2
import org.springframework.context.annotation.Configuration;
3
import org.springframework.scheduling.annotation.EnableAsync;
4
5
@Configuration
6
@ComponentScan("com.thread.demo1")//配置包扫描
7
@EnableAsync //配置异步
8
public class Config {
9
10
}
11
DemoService.java
1
import org.springframework.scheduling.annotation.Async;
2
import org.springframework.stereotype.Service;
3
4
@Service
5
public class DemoService {
6
@Async
7
public void a(){
8
while (true){
9
System.out.println("a");
10
try {
11
Thread.sleep(1000);
12
} catch (InterruptedException e) {
13
e.printStackTrace();
14
}
15
}
16
17
}
18
@Async
19
public void b(){
20
21
while (true){
22
System.out.println("b");
23
try {
24
Thread.sleep(1000);
25
} catch (InterruptedException e) {
26
e.printStackTrace();
27
}
28
}
29
30
}
31
}
32
Main.java
1
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
2
3
public class Main {
4
public static void main(String[] args) {
5
//加载配置文件
6
AnnotationConfigApplicationContext ac=new AnnotationConfigApplicationContext(Config.class);
7
//加载service类
8
DemoService ds=ac.getBean(DemoService.class);
9
//执行类中的方法
10
ds.a();
11
ds.b();
12
}
13
}
活跃性问题:
死锁
a拥有b需要资源,b也有a需要的资源,哥俩都不释放资源。
饥饿
一块挤着抢吃饭,一直抢不到饭,就被饿死了(线程一直得不到资源)。
饥饿相对应的是公平
饥饿与公平(情景)
高优先级吞噬所有低优先级的cpu时间片
线程永久被阻塞在一个等待进入同步快饿状态
等待线程永远不会被唤醒
如何尽量避饥饿问题:
设置合理的优先级
使用锁来代替synchronized
活锁
让路,然后又在另一条路相遇,又让路,又相遇,反反复复。
性能问题:
多线程执行并不一定快,多线程并一定运行在多核处理器或多个处理器,单个处理器也可以运行多个线程。
时间片:cpu会给每个线程分配一个非常短的时间片,执行完后切换到下一个任务,叫做上下文切换,cpu通过一定算法轮流的切换任务,切换的时候要保存执行状态(因为线程并不一定会在时间片里被执行完),在这个过程中要消耗资源。
线程安全问题:
一个线程在执行的过程中,cpu时间片切换,未执行完的线程被另一条线程所写入的数据所覆盖,形成线程不安全。
多线程环境下
多个线程共享一个资源
对资源进行非原子性操作。
struts2的antion不是线程安全的,要把他设置成为多例。
线程的主题往往都是解决线程安全的问题。
解决线程安全问题
Synchronized原理与使用
内置锁:每一个java类都可以做一个内置锁。
互斥锁:一个线程进来,另一个线程不能进来
原子性:
Synchronized修饰普通方法,内置锁就是当前类的实例。
Synchronized修饰静态方法,
Synchronized修饰代码块。
(锁的概念)任何对象都可以作为锁,那么锁信息又存在对象的什么地方呢?
存在对象头中。
对象头中的信息
Mark Word
线程id
Epoch
对象的分代年龄信息
是否是偏向锁
锁标志位
Class Metada Address
Array Lenth(数组有)
各种锁
偏向锁
每次获取锁和释放锁,会浪费资源
很多情况下,竞争锁不是由多个线程,而是由一个线程在使用。
当多个线程竞争偏向锁的时候他才会释放锁,否者会一直持有锁。
只有一个线程在访问同步代码块的场景。
轻量级锁
多个线程可以同时进入代码块,但不能执行下面的代码,只是在不断自旋。
自旋:自旋就是不断的进行请求,浪费资源。
重量级锁
一个线程拥有则另一个线程必须等待。
单利模式与线程安全问题
懒汉式
进行多线程的时候有非原子性操作。
1
//双重判断加锁
2
if(instance==null){
3
synchronized(Singleton.class){
4
if(instance==null){
5
insatnce =new Singleton();
指令重排序。
饿汉式
没有线程安全问题
详细解释锁的概念:
锁重入
a方法被加入入了synchronized锁,在这个方法中调用另一个被加入了synchronized锁的方法b,就会进行锁的重入。
同一个对像的锁只能锁住这个对象的线程,不能锁住其他对象的线程。
1
2
public class Demo {
3
public synchronized void a(){
4
System.out.println("a");
5
try {
6
Thread.sleep(1000);
7
} catch (InterruptedException e) {
8
e.printStackTrace();
9
}
10
// b();
11
}
12
public synchronized void b(){
13
System.out.println("b");
14
try {
15
Thread.sleep(1000);
16
} catch (InterruptedException e) {
17
e.printStackTrace();
18
}
19
}
20
21
public static void main(String[] args) {
22
23
Demo d=new Demo();
24
Demo d2=new Demo();
25
new Thread(new Runnable() {
26
@Override
27
public void run() {
28
// Demo d=new Demo();
29
d.a();
30
}
31
}).start();
32
33
34
new Thread(new Runnable() {
35
@Override
36
public void run() {
37
38
d2.b();
39
}
40
}).start();
41
}
42
43
}
44
自旋锁
线程自己在不停地旋转,旋的是CPU时间片,空转cpu,当第一个线程没有执行完毕的时候,其他线程在自旋等待。
死锁
1
2
public class Demo3 {
3
4
private Object object1=new Object();
5
private Object object2=new Object();
6
7
public void a(){
8
synchronized (object1){
9
try {
10
Thread.sleep(10);
11
} catch (InterruptedException e) {
12
e.printStackTrace();
13
}
14
synchronized (object2){
15
System.out.println("a");
16
}
17
}
18
}
19
20
public void b(){
21
synchronized (object2){
22
try {
23
Thread.sleep(10);
24
} catch (InterruptedException e) {
25
e.printStackTrace();
26
}
27
synchronized (object1){
28
System.out.println("b");
29
}
30
}
31
}
32
33
public static void main(String[] args) {
34
Demo3 d5=new Demo3();
35
new Thread(new Runnable() {
36
@Override
37
public void run() {
38
d5.a();
39
}
40
}).start();
41
Demo3 d=new Demo3();
42
new Thread(new Runnable() {
43
@Override
44
public void run() {
45
d5.b();
46
}
47
}).start();
48
}
49
50
}
51
数据库中如果发生了死锁,会把死锁的资源给释放掉,很强大。
Volatile
Volatile称之为轻量级锁,被vola修饰的变量,在线程之间是可见的。
可见:一个线程修改了这个变量的值,在另一个线程中能够读到这个修改的值。
Synchronized:除了线程之间互斥外,还有一个非常强大的作用,就是保证可见性。
1
2
public class Demo3 {
3
4
private Object object1=new Object();
5
private Object object2=new Object();
6
7
public void a(){
8
synchronized (object1){
9
try {
10
Thread.sleep(10);
11
} catch (InterruptedException e) {
12
e.printStackTrace();
13
}
14
synchronized (object2){
15
System.out.println("a");
16
}
17
}
18
}
19
20
public void b(){
21
synchronized (object2){
22
try {
23
Thread.sleep(10);
24
} catch (InterruptedException e) {
25
e.printStackTrace();
26
}
27
synchronized (object1){
28
System.out.println("b");
29
}
30
}
31
}
32
33
public static void main(String[] args) {
34
Demo3 d5=new Demo3();
35
new Thread(new Runnable() {
36
@Override
37
public void run() {
38
d5.a();
39
}
40
}).start();
41
Demo3 d=new Demo3();
42
new Thread(new Runnable() {
43
@Override
44
public void run() {
45
d5.b();
46
}
47
}).start();
48
}
49
50
}
51
Lock
在多处理器上的系统
将当前处理器缓存行(cpu缓存的最小单位)的内容写回到系统内存
这个写回到内存的操作会使其他cpu里缓存了该内存地址的数据失效
硬盘 --内存--cpu的缓存。
valatile修饰的变量是保证了可见性,但保证不了原子性。
synchronized可以保证原子性和可见性,是在某些方面可以完全替代valatile。
jdk5提供的原子类原理和使用
通过get()方法获取当前的值current
对他进行操作后获取下一个值next
cas方法和下一个值进行比较,如果为真就返回current值,就是线程没有被没有被修改
如果为false就表明被修改过,那就再来一遍。
原子更新基本类型
1
2
import java.util.concurrent.atomic.AtomicInteger;
3
4
public class Sequence {
5
//原子类基本类型
6
private AtomicInteger value=new AtomicInteger();
7
8
9
public int getNext(){
10
return value.getAndAdd(10);
11
12
}
13
14
15
public static void main(String[] args) {
16
17
Sequence s=new Sequence();
18
// while (true){
19
// System.out.println(s.getNext());
20
// }
21
new Thread(new Runnable() {
22
@Override
23
public void run() {
24
while (true){
25
System.out.println(Thread.currentThread().getName()+" "+s.getNext());
26
try {
27
Thread.sleep(100);
28
} catch (InterruptedException e) {
29
e.printStackTrace();
30
}
31
}
32
}
33
}).start();
34
35
new Thread(new Runnable() {
36
@Override
37
public void run() {
38
while (true){
39
System.out.println(Thread.currentThread().getName()+" "+s.getNext());
40
try {
41
Thread.sleep(100);
42
} catch (InterruptedException e) {
43
e.printStackTrace();
44
}
45
}
46
}
47
}).start();
48
49
new Thread(new Runnable() {
50
@Override
51
public void run() {
52
while (true){
53
System.out.println(Thread.currentThread().getName()+" "+s.getNext());
54
try {
55
Thread.sleep(100);
56
} catch (InterruptedException e) {
57
e.printStackTrace();
58
}
59
}
60
}
61
}).start();
62
}
63
}
64
原子更新数组
原子更新抽象类型
原子更新字段
1
2
import java.util.concurrent.atomic.AtomicInteger;
3
import java.util.concurrent.atomic.AtomicIntegerArray;
4
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
5
import java.util.concurrent.atomic.AtomicReference;
6
7
public class Sequence {
8
//原子类基本类型
9
private AtomicInteger value=new AtomicInteger();
10
//原子跟新数组
11
private int[] s={2,1,3,4};
12
AtomicIntegerArray a=new AtomicIntegerArray(s);
13
//原子更新抽象类型
14
AtomicReference user=new AtomicReference<>();
15
//原子跟新字段要更新的字段必须要进行valatile修饰
16
AtomicIntegerFieldUpdater ord =AtomicIntegerFieldUpdater.newUpdater(User.class,"ord");
17
18
public int getNext(){
19
User user=new User();
20
System.out.println( ord.getAndIncrement(user));
21
System.out.println( ord.getAndIncrement(user));
22
System.out.println( ord.getAndIncrement(user));
23
24
a.getAndIncrement(2);
25
a.getAndAdd(2,10);
26
return value.getAndAdd(10);
27
28
}
29
30
31
public static void main(String[] args) {
32
33
Sequence s=new Sequence();
34
// while (true){
35
// System.out.println(s.getNext());
36
// }
37
new Thread(new Runnable() {
38
@Override
39
public void run() {
40
while (true){
41
System.out.println(Thread.currentThread().getName()+" "+s.getNext());
42
try {
43
Thread.sleep(100);
44
} catch (InterruptedException e) {
45
e.printStackTrace();
46
}
47
}
48
}
49
}).start();
50
51
new Thread(new Runnable() {
52
@Override
53
public void run() {
54
while (true){
55
System.out.println(Thread.currentThread().getName()+" "+s.getNext());
56
try {
57
Thread.sleep(100);
58
} catch (InterruptedException e) {
59
e.printStackTrace();
60
}
61
}
62
}
63
}).start();
64
65
new Thread(new Runnable() {
66
@Override
67
public void run() {
68
while (true){
69
System.out.println(Thread.currentThread().getName()+" "+s.getNext());
70
try {
71
Thread.sleep(100);
72
} catch (InterruptedException e) {
73
e.printStackTrace();
74
}
75
}
76
}
77
}).start();
78
}
79
}
80
Lock接口