Skip to content

Commit 9c1fdcc

Browse files
committed
增加CAS,集合类线程安全,锁
1 parent 48bf16c commit 9c1fdcc

File tree

10 files changed

+451
-1
lines changed

10 files changed

+451
-1
lines changed

pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@
66
<groupId>net.cdsunrise.interview.advanced</groupId>
77
<artifactId>getoffer</artifactId>
88
<version>1.0</version>
9+
<dependencies>
10+
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
11+
<dependency>
12+
<groupId>org.projectlombok</groupId>
13+
<artifactId>lombok</artifactId>
14+
<version>1.18.12</version>
15+
<scope>provided</scope>
16+
</dependency>
17+
</dependencies>
18+
919

1020
<properties/>
1121
</project>
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.atguigu.interview.juc;
2+
3+
import java.util.concurrent.atomic.AtomicReference;
4+
import java.util.concurrent.atomic.AtomicStampedReference;
5+
6+
/**
7+
* @author
8+
*/
9+
public class ABADemo {
10+
static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
11+
static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100,1);
12+
public static void main(String[] args) {
13+
System.out.println("----------------ABA Demo------------------");
14+
new Thread(() -> {
15+
atomicReference.compareAndSet(100, 101);
16+
atomicReference.compareAndSet(101, 100);
17+
}, "t1").start();
18+
19+
new Thread(() -> {
20+
try {
21+
// 保证t1线程完成一次ABA
22+
Thread.sleep(1000L);
23+
System.out.println(atomicReference.compareAndSet(100, 102) +
24+
"\t" + atomicReference.get());
25+
} catch (Exception e) {
26+
e.printStackTrace();
27+
}
28+
}, "t2").start();
29+
30+
System.out.println("----------------ABA Solution------------------");
31+
new Thread(() -> {
32+
int stamp = atomicStampedReference.getStamp();
33+
System.out.println(Thread.currentThread().getName() + "\t第1次版本号" + stamp);
34+
try {Thread.sleep(1000L);} catch (Exception e) {e.printStackTrace();}
35+
atomicStampedReference.compareAndSet(100, 101,
36+
atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
37+
System.out.println(Thread.currentThread().getName() + "\t第2次版本号" + atomicStampedReference.getStamp());
38+
atomicStampedReference.compareAndSet(101, 100,
39+
atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
40+
System.out.println(Thread.currentThread().getName() + "\t第3次版本号" + atomicStampedReference.getStamp());
41+
42+
}, "t3").start();
43+
44+
new Thread(() -> {
45+
int stamp = atomicStampedReference.getStamp();
46+
System.out.println(Thread.currentThread().getName() + "\t第1次版本号" + stamp);
47+
try {Thread.sleep(3000L);} catch (Exception e) {e.printStackTrace();}
48+
boolean b = atomicStampedReference.compareAndSet(100, 102,
49+
stamp, stamp + 1);
50+
System.out.println(Thread.currentThread().getName()+"\t 修改成功:"+b);
51+
}, "t4").start();
52+
53+
}
54+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.atguigu.interview.juc;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
import lombok.ToString;
6+
7+
import java.util.concurrent.atomic.AtomicReference;
8+
9+
/**
10+
* @author
11+
* CAS->Unsafe->CAS底层思想->ABA->原子引用更新->如何规避ABA问题
12+
*/
13+
public class AtomicReferenceDemo {
14+
public static void main(String[] args){
15+
User z3 = new User("z3",22);
16+
User l4 = new User("l4",25);
17+
AtomicReference<User> atomicReference = new AtomicReference<>();
18+
atomicReference.set(z3);
19+
System.out.println(atomicReference.compareAndSet(z3,l4)+"\t"+atomicReference.get());
20+
System.out.println(atomicReference.compareAndSet(z3,l4)+"\t"+atomicReference.get());
21+
22+
}
23+
}
24+
25+
@Data
26+
@ToString
27+
@AllArgsConstructor
28+
class User{
29+
String userName;
30+
int age;
31+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.atguigu.interview.juc;
2+
3+
import java.util.concurrent.atomic.AtomicInteger;
4+
5+
/**
6+
* @author
7+
* CAS 比较并交换
8+
*/
9+
public class CASDemo {
10+
public static void main(String[] args){
11+
AtomicInteger atomicInteger = new AtomicInteger();
12+
System.out.println(atomicInteger.compareAndSet(0,1)+" current data = "+atomicInteger.get());
13+
System.out.println(atomicInteger.compareAndSet(0,2)+" current data = "+atomicInteger.get());
14+
atomicInteger.getAndIncrement();
15+
}
16+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.atguigu.interview.juc;
2+
3+
import java.util.*;
4+
import java.util.concurrent.ConcurrentHashMap;
5+
import java.util.concurrent.CopyOnWriteArrayList;
6+
import java.util.concurrent.CopyOnWriteArraySet;
7+
8+
/**
9+
* @author
10+
*/
11+
public class ContainerNotSafeDemo {
12+
public static void main(String[] args){
13+
mapNotSafe();
14+
}
15+
16+
private static void mapNotSafe() {
17+
Map<String,String> map = new ConcurrentHashMap<>();
18+
for (int i = 0; i < 30; i++) {
19+
new Thread(()->{
20+
map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,8));
21+
System.out.println(map);
22+
},String.valueOf(i)).start();
23+
}
24+
}
25+
26+
private static void setNotSafe() {
27+
Set<String> set = new CopyOnWriteArraySet<>();
28+
for (int i = 0; i < 30; i++) {
29+
new Thread(()->{
30+
set.add(UUID.randomUUID().toString().substring(0,8));
31+
System.out.println(set);
32+
},String.valueOf(i)).start();
33+
}
34+
// HashSet 与 HashMap
35+
new HashSet<String>().add("a");
36+
}
37+
38+
private static void listNotSafe() {
39+
List<String> list = new CopyOnWriteArrayList<>();
40+
for (int i = 0; i < 30; i++) {
41+
new Thread(()->{
42+
list.add(UUID.randomUUID().toString().substring(0,8));
43+
System.out.println(list);
44+
},String.valueOf(i)).start();
45+
}
46+
47+
/**
48+
* 故障现场
49+
* java.util.ConcurrentModificationException
50+
* 导致原因
51+
*
52+
* 解决方案
53+
* 1.new Vector<>();
54+
* 2.Collections.synchronizedList(new ArrayList<>());
55+
* 3.CopyOnWriteArrayList();
56+
* CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,
57+
* 不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容
58+
* 器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们
59+
* 可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。
60+
* 所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
61+
* CopyOnWrite的缺点
62+
*   内存占用问题。因为CopyOnWrite的写时复制机制,所以在进行写操作的时候,内存
63+
* 里会同时驻扎两个对象的内存,旧的对象和新写入的对象(注意:在复制的时候只是复制容
64+
* 器里的引用,只是在写的时候会创建新对象添加到新容器里,而旧容器的对象还在使用,
65+
* 所以有两份对象内存)。如果这些对象占用的内存比较大,比如说200M左右,那么再
66+
* 写入100M数据进去,内存就会占用300M,那么这个时候很有可能造成频繁的Yong GC和Full GC。
67+
* 之前我们系统中使用了一个服务由于每晚使用CopyOnWrite机制更新大对象,造成了每晚15秒的
68+
* Full GC,应用响应时间也随之变长。
69+
*   针对内存占用问题,可以通过压缩容器中的元素的方法来减少大对象的内存消耗,比如,如果
70+
* 元素全是10进制的数字,可以考虑把它压缩成36进制或64进制。或者不使用CopyOnWrite容器,
71+
* 而使用其他的并发容器,如ConcurrentHashMap。
72+
*
73+
*   数据一致性问题。CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。
74+
* 所以如果你希望写入的的数据,马上能读到,请不要使用CopyOnWrite容器。
75+
*/}
76+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.atguigu.interview.juc;
2+
3+
import java.util.concurrent.atomic.AtomicReference;
4+
import java.util.concurrent.atomic.AtomicStampedReference;
5+
import java.util.concurrent.locks.Lock;
6+
import java.util.concurrent.locks.ReentrantLock;
7+
8+
/**
9+
* @author
10+
*/
11+
public class LockDemo {
12+
public static void main(String[] args){
13+
// 默认非公平锁
14+
// 可重入锁 避免死锁
15+
ReentrantLock lock = new ReentrantLock();
16+
17+
// synchronized 可重入锁
18+
Phone phone = new Phone();
19+
new Thread(()->{phone.sendMsg();},"t1").start();
20+
new Thread(()->{phone.sendMsg();},"t2").start();
21+
22+
// ReentrantLock 可重入锁
23+
new Thread(phone).start();
24+
new Thread(phone).start();
25+
26+
// 自旋锁 spinlock CAS核心原理
27+
// 尝试获取锁的线程不会阻塞,而是采用循环的方式尝试获取锁。
28+
29+
}
30+
}
31+
32+
class Phone implements Runnable{
33+
public synchronized void sendMsg() {
34+
System.out.println(Thread.currentThread().getName()+"\t invoked sendMsg()");
35+
sendEmail();
36+
}
37+
public synchronized void sendEmail() {
38+
System.out.println(Thread.currentThread().getName()+"\t invoked sendEmail()");
39+
}
40+
41+
Lock lock = new ReentrantLock();
42+
@Override
43+
public void run() {
44+
get();
45+
}
46+
public void get(){
47+
// 可多次加锁,只要和unlock匹配即可
48+
lock.lock();
49+
try {
50+
System.out.println(Thread.currentThread().getName()+"\t invoked get()");
51+
set();
52+
}finally {
53+
lock.unlock();
54+
}
55+
}
56+
public void set(){
57+
lock.lock();
58+
try {
59+
System.out.println(Thread.currentThread().getName()+"\t invoked set()");
60+
}finally {
61+
lock.unlock();
62+
}
63+
}
64+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.atguigu.interview.juc;
2+
3+
import java.util.Map;
4+
import java.util.concurrent.ConcurrentHashMap;
5+
import java.util.concurrent.TimeUnit;
6+
import java.util.concurrent.locks.ReadWriteLock;
7+
import java.util.concurrent.locks.ReentrantReadWriteLock;
8+
9+
/**
10+
* @author
11+
*/
12+
public class ReadWriteLockDemo {
13+
public static void main(String[] args){
14+
MyCache cache = new MyCache();
15+
for (int i = 0; i < 5; i++) {
16+
final int temp = i;
17+
new Thread(()->{
18+
cache.put(String.valueOf(temp),temp);
19+
},String.valueOf(i)).start();
20+
}
21+
for (int i = 0; i < 5; i++) {
22+
final int temp = i;
23+
new Thread(()->{
24+
cache.get(String.valueOf(temp));
25+
},String.valueOf(i)).start();
26+
}
27+
}
28+
}
29+
30+
class MyCache{
31+
private volatile Map<String,Object> map = new ConcurrentHashMap<>();
32+
/**
33+
* 尝试注释锁,体验效果
34+
*/
35+
private ReadWriteLock lock = new ReentrantReadWriteLock();
36+
37+
public void put(String key,Object value){
38+
System.out.println(Thread.currentThread().getName()+"\t 正在写入");
39+
lock.writeLock().lock();
40+
try {
41+
TimeUnit.MILLISECONDS.sleep(300L);
42+
map.put(key, value);
43+
System.out.println(Thread.currentThread().getName()+"\t 写入完成");
44+
} catch(Exception e) {
45+
e.printStackTrace();
46+
}finally {
47+
lock.writeLock().unlock();
48+
}
49+
}
50+
51+
public void get(String key){
52+
System.out.println(Thread.currentThread().getName()+"\t 正在读取");
53+
lock.readLock().lock();
54+
try {
55+
TimeUnit.MILLISECONDS.sleep(100L);
56+
Object o = map.get(key);
57+
System.out.println(Thread.currentThread().getName()+"\t 读取完成" + o);
58+
} catch(Exception e) {
59+
e.printStackTrace();
60+
}finally {
61+
lock.readLock().unlock();
62+
}
63+
}
64+
65+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.atguigu.interview.juc;
2+
3+
/**
4+
* @author
5+
*
6+
*/
7+
public class Singleton {
8+
private static volatile Singleton instance = null;
9+
private Singleton(){
10+
System.out.println(Thread.currentThread().getName()+" 创建单例");
11+
}
12+
13+
/**
14+
* 懒汉模式
15+
* 存在多线程问题
16+
* @return
17+
*/
18+
public static Singleton getInstance() {
19+
if(instance == null){
20+
instance = new Singleton();
21+
}
22+
return instance;
23+
}
24+
25+
/**
26+
* DCL(double check lock)+ volatile
27+
* @return
28+
*/
29+
public static Singleton getDCLInstance() {
30+
if(instance == null){
31+
synchronized (Singleton.class){
32+
if(instance == null){
33+
instance = new Singleton();
34+
}
35+
}
36+
}
37+
return instance;
38+
}
39+
40+
public static void main(String[] args){
41+
// 单线程环境
42+
// System.out.println("单线程环境:");
43+
// System.out.println(Singleton.getInstance() == Singleton.getInstance());
44+
45+
// 多线程并发环境
46+
System.out.println("多线程并发环境:");
47+
for (int i = 0; i < 10 ; i++) {
48+
new Thread(()->{
49+
Singleton.getDCLInstance();
50+
}).start();
51+
}
52+
}
53+
}

0 commit comments

Comments
 (0)