1、原子引用
package com.example.mybaties;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
import java.util.concurrent.atomic.AtomicReference;
/**
* @DESCRIPTION 原子引用
* @Author lst
* @Date 2020-03-24 09:00
*/
public class AtomicReferenceDemo {
public static void main(String[] args) {
User z3 = new User("z3",22);
User li4 = new User("li4",25);
AtomicReference<User> atomicReference = new AtomicReference();
atomicReference.set(z3);
System.out.println(atomicReference.compareAndSet(z3,li4)+ "\t " + atomicReference.get().toString());
System.out.println(atomicReference.compareAndSet(z3,li4)+ "\t " + atomicReference.get().toString());//主物理内存已经变成li4
/**
* true User(userName=li4, age=25)
* false User(userName=li4, age=25)
*/
}
}
@Getter
@ToString
@AllArgsConstructor
class User {
String userName;
int age;
}
2、可重入锁
package com.example.mybaties;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @DESCRIPTION 可重入锁(也叫递归锁)
* 指的是同一线程外层脳数获得锁之后,内层递归数仍然能获取该锁的代吗,在同一个线程在外层方法英取的时候,
* 在进入内层方法会自动获取锁也即是说,线程可以进入一个任何它已经拥有的所同歩的代码块
*
*
* 就是一个典型的可重入锁
*
* 11invoked sendSms
* 11#######invoked sendEmail
* 12invoked sendSms
* 12#######invoked sendEmail
*
*
*
* @Author lst
* @Date 2020-03-23 14:48
*/
class Phone implements Runnable{
public synchronized void sendSms(){
System.out.println(Thread.currentThread().getId() + "invoked sendSms ");
sendEmail();
}
public synchronized void sendEmail(){
System.out.println(Thread.currentThread().getId() + "#######invoked sendEmail ");
}
Lock lock = new ReentrantLock();//默认非公平锁
@Override
public void run() {
get();
}
public void get(){
lock.lock();
lock.lock();
System.out.println(Thread.currentThread().getName() + " invoked get() ");
set();
lock.unlock();
lock.unlock();
}
public void set(){
lock.lock();
System.out.println(Thread.currentThread().getName() + " ####invoked set() ");
lock.unlock();
}
}
public class ReenterLockDemo {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() -> {
phone.sendSms();
},"t1").start();
new Thread(() -> {
phone.sendSms();
},"t2").start();
//暂停一会
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println();
System.out.println();
System.out.println();
System.out.println();
System.out.println();
Thread t3 = new Thread(phone,"t3");
Thread t4 = new Thread(phone,"t4");
t3.start();
t4.start();
/**
* 14invoked sendSms
* 14#######invoked sendEmail
* 13invoked sendSms
* 13#######invoked sendEmail
*
*
*
*
*
* t3 invoked get()
* t3 ####invoked set()
* t4 invoked get()
* t4 ####invoked set()
*/
}
}
3、读写锁
/**
* @DESCRIPTION 读写锁
*多个线程同时读一个资源关没有任何问题,所以为了满足并发量,读取共享资源应该可以同时进行
* 但是如果有一个线程想去写共享资源来,就不应该再有其它线程可以对该资源进行读或写
* 小总结
* 读-读能共存
* 读-写不能共存
* 写不能共存
*
*
* 写操作:原子(完整一致性)+独占,整个过程必须是一个完整的统一体,中间不能间断
*
* @Author lst
* @Date 2020-03-24 12:00
*/
class MyCache { //资源类
private volatile Map<String,Object> map = new HashMap<>();
private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
public void put(String key,Object value){
//写锁
rwLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()+" 正在写入: " +key);
//暂停一会线程
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put(key,value);
System.out.println(Thread.currentThread().getName()+" 写入完成: " );
}catch (Exception e){
e.getMessage();
}finally {
rwLock.writeLock().unlock();
}
}
public void get(String key){
//读锁
rwLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName()+" 正在读取: " +key);
//暂停一会线程
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
Object result = map.get(key);
System.out.println(Thread.currentThread().getName()+" 读取完成: " + result);
}catch (Exception e){
e.getMessage();
}finally {
rwLock.readLock().unlock();
}
}
public void clearMap(){
map.clear();
}
}
public class ReentranRreadWriteLockDemo {
public static void main(String[] args) {
MyCache myCache = new MyCache();
for (int i = 0; i < 5; i++) {
final String keyValue = String.valueOf(i);
new Thread(() -> {
myCache.put(keyValue,keyValue);
},keyValue).start();
}
for (int i = 0; i < 5; i++) {
final String keyValue = String.valueOf(i);
new Thread(() -> {
myCache.get(keyValue);
},keyValue).start();
}
/* 0 正在写入: 0
0 写入完成:
1 正在写入: 1
1 写入完成:
2 正在写入: 2
2 写入完成:
3 正在写入: 3
3 写入完成:
4 正在写入: 4
4 写入完成:
0 正在读取: 0
1 正在读取: 1
2 正在读取: 2
3 正在读取: 3
4 正在读取: 4
0 读取完成: 0
1 读取完成: 1
2 读取完成: 2
3 读取完成: 3
4 读取完成: 4
*/
ShareResource shareResource = new ShareResource();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
shareResource.print5();
}
},"A").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
shareResource.print10();
}
},"B").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
shareResource.print15();
}
},"C").start();
}
}
4、synchronized和lock有什么区别?用新的lock有什么好处?你挙例说说
/**
* 题目: synchronized 和lock有什么区别?用新的lock有什么好处?你挙例说说
* 1、原始构成
* synchronized是关字jvm层面,
* monitorenter(底层是通过monitor对象来完成,其实wait/ notify等方法也依 monitor对象只有在同步块或方法中能源ait/ notify等方
* monitorexit
* Lock是具体类(java,utiL, concurrent. Locks.Lock)是api层面的锁
* 2、使用方法
* synchronized 不需要用户去手动释放锁,当 synchronized代码执行完后系统会自动让线程释放对锁的占用
* Reentrantlock则需要户去手动释放锁,若没有主动释放锁,就有可能导致出现死锁现象。需要Lock()和unLock()方法配合try/ finally语句块来完成
* 3、等待是否可中断
* synchronized 不可中断,除非抛出异常或者正常运行完成
* Reentrantlock 可中断,
* 1.设置超时方法 trylock( long timeout, Timeunit unit)
* 2. LockInterruptibly()放代码块中,调 interrupt()方法可中断
* 4、加锁是否公平
* synchronized非公平锁
* Reentrantlock 两者都可以,默认非公平锁,构造方法可以传入 boolean值,true为公平锁, false为非公平锁
*
* 5、锁绑定多个条件 Condition
* synchronized没有
* Reentrantlock,用来实分组唤要唤的线程,可以精确唤醒,而不是像 synchronized要么随机唤醒一个线程 要么唤醒全部线程
*
*
* 原始构成:synchronized是JVM层面的,底层通过monitorenter和monitorexit来实现的。Lock是JDK API层面的。(synchronized一个enter会有两个exit,一个是正常退出,一个是异常退出(保证肯定可以退出))
* 使用方法:synchronized不需要手动释放锁,而Lock需要手动释放。
* 是否可中断:synchronized不可中断,除非抛出异常或者正常运行完成。Lock是可中断的,1.设置超时方法tryLock(long timeout,TimeUnit unit); 2. lockInterruptibly()方法放代码块中,调用interrupt()
* 是否为公平锁:synchronized只能是非公平锁,而ReentrantLock既能是公平锁,又能是非公平锁,构造方法传入false/true,默认是非公平锁false。
* 绑定多个条件:synchronized不能,只能随机唤醒。而Lock可以通过Condition来绑定多个条件,精确唤醒。
*
*
* 题目:多线程之按顺序调用,实现A->B->C三个线程启动,要求如下
* AA打印5次,BB打印10次,CC打印15次
* 紧接着
* AA打印5次,BB打印10次,CC打印15次
* 。。。。。。
* 来10轮
*
*/
class ShareResource{
private int number = 1;//A:1 B:2 C:3
private Lock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();
public void print5(){
lock.lock();
try{
//1、判断
while (number != 1){
c1.await();
}
//2、干活
for (int i = 1; i <= 5 ; i++) {
System.out.println(Thread.currentThread().getName()+" " + i);
}
//3、通知
number = 2;
c2.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void print10(){
lock.lock();
try{
//1、判断
while (number != 2){
c2.await();
}
//2、干活
for (int i = 1; i <= 10 ; i++) {
System.out.println(Thread.currentThread().getName()+" " + i);
}
//3、通知
number = 3;
c3.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void print15(){
lock.lock();
try{
//1、判断
while (number != 3){
c3.await();
}
//2、干活
for (int i = 1; i <= 15 ; i++) {
System.out.println(Thread.currentThread().getName()+" " + i);
}
//3、通知
number = 1;
c3.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}