ReentrantLock:可重入锁
ReentrantReadWriteLock.ReadLock:读锁
ReentrantReadWriteLock.WriteLock:写锁
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
// 默认非公平锁
public class SaleTicketDemo02 {
public static void main(String[] args) {
// 并发,多线程操作同一个资源类
Ticket2 ticket = new Ticket2();
// lambda表达式(参数)->{代码}
new Thread(()->{
for (int i = 0;i < 40;i++) ticket.sale();},"A").start();
new Thread(()->{
for (int i = 0;i < 40;i++) ticket.sale();},"B").start();
new Thread(()->{
for (int i = 0;i < 40;i++) ticket.sale();},"C").start();
}
}
class Ticket2 {
private int number = 30;
Lock lock = new ReentrantLock();
public synchronized void sale() {
lock.lock();
try {
if (number > 0) {
System.out.println(Thread.currentThread().getName() + "卖出了第" + (number--) + "张票,剩余:" + number);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
Synchronized锁
public class SaleTicketDemo01 {
public static void main(String[] args) {
// 并发,多线程操作同一个资源类
Ticket ticket = new Ticket();
// lambda表达式(参数)->{代码}
new Thread(()->{
for (int i = 0;i < 40;i++) ticket.sale();},"A").start();
new Thread(()->{
for (int i = 0;i < 40;i++) ticket.sale();},"B").start();
new Thread(()->{
for (int i = 0;i < 40;i++) ticket.sale();},"C").start();
}
}
class Ticket {
private int number = 30;
public synchronized void sale() {
if (number > 0) {
System.out.println(Thread.currentThread().getName() + "卖出了第" + (number--) + "张票,剩余:" + number);
}
}
}
Synchronized锁与Lock锁区别
1.Synchronized是内置关键字,Lock是一个Java类
2.Synchronized无法判断获取锁的状态,Lock可以判断是否获取到了锁
3.Synchronized会自动释放锁,Lock需要手动释放锁
4.Synchronized线程一获得锁阻塞后,线程二会一直等待;Lock锁不一定会等待下去
5.Synchronized是可重入锁,不可以中断,非公平;Lock,可重入锁,可以判断锁,非公平
6.Synchronized适合少量的代码同步问题,Lock适合锁大量的同步代码
Synchronized
public class Test1 {
public static void main(String[] args) {
Resource resource = new Resource();
new Thread(()->{
for (int i = 0;i < 10;i++) {
try {
resource.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0;i < 10;i++) {
try {
resource.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0;i < 10;i++) {
try {
resource.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0;i < 10;i++) {
try {
resource.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
class Resource {
private int num = 0;
public synchronized void increment() throws InterruptedException {
while (num != 0) {
// 等待
this.wait();
}
num++;
System.out.println(Thread.currentThread().getName()+"=>"+num);
// 通知线程+1完毕
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
while (num == 0) {
// 等待
this.wait();
}
num--;
System.out.println(Thread.currentThread().getName()+"=>"+num);
// 通知线程-1完毕
this.notifyAll();
}
}
Lock
public class Test2 {
public static void main(String[] args) {
Resource resource = new Resource();
new Thread(()->{
for (int i = 0;i < 10;i++) {
try {
resource.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0;i < 10;i++) {
try {
resource.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0;i < 10;i++) {
try {
resource.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0;i < 10;i++) {
try {
resource.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
class Resource2 {
private int num = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public synchronized void increment() throws InterruptedException {
lock.lock();
try {
while (num != 0) {
// 等待
condition.await();
}
num++;
System.out.println(Thread.currentThread().getName()+"=>"+num);
// 通知线程+1完毕
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public synchronized void decrement() throws InterruptedException {
lock.lock();
try {
while (num == 0) {
// 等待
condition.await();
}
num--;
System.out.println(Thread.currentThread().getName()+"=>"+num);
// 通知线程-1完毕
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
Condition精准的通知唤醒线程
// A执行完调用B,B执行完调用C,C执行完调用A
public class Test3 {
public static void main(String[] args) {
Resource3 resource3 = new Resource3();
new Thread(()->{
for (int i = 0;i < 10;i++) {
resource3.printA();
}
},"A").start();
new Thread(()->{
for (int i = 0;i < 10;i++) {
resource3.printB();
}
},"B").start();
new Thread(()->{
for (int i = 0;i < 10;i++) {
resource3.printC();
}
},"C").start();
}
}
class Resource3 {
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
private int number = 1;
public void printA() {
lock.lock();
try {
while (number != 1) {
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"=>AAA");
number = 2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
while (number != 2) {
condition2.await();
}
System.out.println(Thread.currentThread().getName()+"=>BBB");
number = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
while (number != 3) {
condition3.await();
}
System.out.println(Thread.currentThread().getName()+"=>CCC");
number = 1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
1.可以有返回值
2.可以抛出异常
3.方法不同
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
new Thread().start();
MyThread thread = new MyThread();
FutureTask<Integer> futureTask = new FutureTask<>(thread);
new Thread(futureTask,"A").start();
Integer integer = futureTask.get();
System.out.println(integer);
}
}
class MyThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("call方法");
return 1024;
}
}
// 减法计数器
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(5);
for (int i = 0;i < 5;i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"go out");
countDownLatch.countDown(); // -1
},String.valueOf(i)).start();
}
countDownLatch.await(); // 等待计数器归零再向下执行
System.out.println("finish");
}
}
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(5,()->{
System.out.println("finish");
});
for (int i = 0;i < 5;i++) {
final int temp = i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"=>"+temp);
try {
cyclicBarrier.await(); // 等待
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
信号量
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for (int i = 0;i < 6;i++) {
new Thread(()->{
// acquire()得到
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+" in");
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+" out");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// release()释放
semaphore.release();
}
}).start();
}
}
}
原理:
acquire:获得,假设已经满了,等待被释放位置
release:释放,会将当前的信号量+1,然后唤醒等待的线程
/**
* 独占锁(写锁):一次只能被一个线程私有
* 共享锁(读锁):多个线程可以同时占有
*/
public class ReadWriteLockTest {
public static void main(String[] args) {
MyCacheLock myCache = new MyCacheLock();
//写入
for (int i = 0; i < 5; i++) {
final int temp = i;
new Thread(()->{
myCache.put(temp+"",temp+"");
},String.valueOf(i)).start();
}
//读取
for (int i = 0; i < 5; i++) {
final int temp = 1;
new Thread(()->{
myCache.get(temp+"");
},String.valueOf(i)).start();
}
}
}
class MyCacheLock{
private volatile Map<String, Object> map = new HashMap<String,Object>();
//读写锁
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
//存,写入的时候,只希望同时只有一个线程写
public void put(String key, Object value){
readWriteLock.writeLock().lock();
try{
System.out.println(Thread.currentThread().getName()+"写入"+key);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入OK");
}catch(Exception e){
e.printStackTrace();
}finally {
readWriteLock.writeLock().unlock();
}
}
//取,读,所有人都可以读!
public void get(String key){
readWriteLock.readLock().lock();
try{
System.out.println(Thread.currentThread().getName()+"读取"+key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取OK");
}catch (Exception e){
e.printStackTrace();
}finally {
readWriteLock.readLock().unlock();
}
}
}
写入:如果队列满了,就必须阻塞等待
读取:如果队列是空的,必须阻塞等待生产
//什么时候使用阻塞队列? 1、多线程并发处理 2、线程池
public class BlockingQueueTest {
public static void main(String[] args) throws InterruptedException {
//四组api
//test1();
//test2();
//test3();
test4();
}
//第一组 : add() remove() 抛出异常
public static void test1() {
ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(arrayBlockingQueue.add("a"));
System.out.println(arrayBlockingQueue.add("b"));
System.out.println(arrayBlockingQueue.add("c"));
//发生异常:java.lang.IllegalStateException: Queue full
//System.out.println(arrayBlockingQueue.add("d"));
System.out.println(arrayBlockingQueue.remove());
System.out.println(arrayBlockingQueue.remove());
System.out.println(arrayBlockingQueue.remove());
//java.util.NoSuchElementException
//System.out.println(arrayBlockingQueue.remove());
}
//第二组: offer() poll() 返回false null
public static void test2(){
ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(arrayBlockingQueue.offer("a"));
System.out.println(arrayBlockingQueue.offer("b"));
System.out.println(arrayBlockingQueue.offer("c"));
//返回false
//System.out.println(arrayBlockingQueue.offer("d"));
System.out.println(arrayBlockingQueue.poll());
System.out.println(arrayBlockingQueue.poll());
System.out.println(arrayBlockingQueue.poll());
//返回null
//System.out.println(arrayBlockingQueue.poll());
}
//第三组: put() take() 一直阻塞
public static void test3() throws InterruptedException {
ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(3);
arrayBlockingQueue.put("a");
arrayBlockingQueue.put("b");
arrayBlockingQueue.put("c");
//一直阻塞
//arrayBlockingQueue.put("d");
System.out.println(arrayBlockingQueue.take());
System.out.println(arrayBlockingQueue.take());
System.out.println(arrayBlockingQueue.take());
//一直阻塞
//System.out.println(arrayBlockingQueue.take());
}
//第四组: offer() poll()
public static void test4() throws InterruptedException {
ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(3);
arrayBlockingQueue.offer("a");
arrayBlockingQueue.offer("b");
arrayBlockingQueue.offer("c");
//超时退出
//arrayBlockingQueue.offer("d",5, TimeUnit.SECONDS);
System.out.println(arrayBlockingQueue.poll());
System.out.println(arrayBlockingQueue.poll());
System.out.println(arrayBlockingQueue.poll());
//超时退出
System.out.println(arrayBlockingQueue.poll(5,TimeUnit.SECONDS));
}
}
SynchronousQueue同步队列
public class SynchronousQueueDemo {
public static void main(String[] args) {
//同步队列
SynchronousQueue<String> synchronousQueue = new SynchronousQueue<>();
//放元素
new Thread(()->{
try{
System.out.println(Thread.currentThread().getName()+"放入1");
synchronousQueue.put("1");
System.out.println(Thread.currentThread().getName()+"放入2");
synchronousQueue.put("2");
System.out.println(Thread.currentThread().getName()+"放入3");
synchronousQueue.put("3");
}catch (Exception e){
e.printStackTrace();
}
},"T1").start();
//取元素
new Thread(()->{
try{
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+"取到"+synchronousQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+"取到"+synchronousQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+"取到"+synchronousQueue.take());
}catch (Exception e){
e.printStackTrace();
}
},"T2").start();
}
}
1.降低资源的消耗
2.提高响应效率,不用创建与销毁
3.方便管理
newSingleThreadExecutor();// 单个线程
newFixedThreadPool();// 创建固定的线程池大小
newCachedThreadPool();// 创建可以伸缩的线程池
public class Demo01 {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor();// 单个线程
ExecutorService threadPool1 = Executors.newFixedThreadPool(5);// 创建固定的线程池大小
ExecutorService threadPool2 = Executors.newCachedThreadPool();// 创建可以伸缩的线程池
try {
for (int i = 0;i < 10;i++) {
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+" OK");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
corePoolSize
核心线程池大小
maximumPoolSize
最大核心线程池大小
keepAliveTime
存活时间
unit
时间单位
workQueue
阻塞队列
threadFactory
线程工厂,创建线程
handle
拒绝策略
public class Demo01 {
public static void main(String[] args) {
ExecutorService threadPool = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
try {
for (int i = 0;i < 8;i++){
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+" OK");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
}
当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize时,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。 ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务
ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
CPU密集型
ExecutorService threadPool = new ThreadPoolExecutor(
2,
Runtime.getRuntime().availableProcessors(),
3,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
Runtime.getRuntime().availableProcessors():获取CPU数
IO密集型
判断程序中十分消耗IO的线程
只有一个方法的接口
函数型接口
// 函数型接口
public class Demo01 {
public static void main(String[] args) {
// Function function = new Function() {
// @Override
// public String apply(String s) {
// return s;
// }
// };
// lambda表达式简化
Function function = (str)->{
return str;};
System.out.println(function.apply("123"));
}
}
断定型接口
// 断定型接口:有一个输入参数,返回只能是布尔值
public class Demo02 {
public static void main(String[] args) {
// 判断字符串是否为空
// Predicate predicate = new Predicate() {
// @Override
// public boolean test(String s) {
// return s.isEmpty();
// }
// };
Predicate<String> predicate = (str)->{
return str.isEmpty();};
System.out.println(predicate.test("123"));
}
}
消费型接口
/*
* 消费型接口,只有输入没有返回值
* */
public class Demo03 {
public static void main(String[] args) {
// Consumer consumer = new Consumer() {
// @Override
// public void accept(String s) {
// System.out.println(s);
// }
// };
Consumer<String> consumer = (str)->{
System.out.println(str); };
consumer.accept("123");
}
}
供给型接口
/*
* 供给型接口,没有参数只有返回值
* */
public class Demo04 {
public static void main(String[] args) {
// Supplier supplier = new Supplier() {
// @Override
// public String get() {
// return "123";
// }
// };
Supplier<String> supplier = ()->{
return "123";};
System.out.println(supplier.get());
}
}
/**
* 题目要求:一分钟内完成此题,只能用一行代码实现!
* 现在有5个用户!筛选:
* 1、密码必须是偶数
* 2、年龄必须大于23岁
* 3、用户名转为大写字母
* 4、用户名字母倒着排序
* 5、只输出一个用户!
*/
//mysql,集合本质是来放东西 计算的东西应该交给流
public class Stream {
public static void main(String[] args) {
User1 u1 = new User1("qk1","1",21);
User1 u2 = new User1("Hk2","2",22);
User1 u3 = new User1("kk3","3",23);
User1 u4 = new User1("Hk4","4",24);
User1 u5 = new User1("ak5","5",25);
//集合就是存储
List<User1> list = Arrays.asList(u1, u2, u3 ,u4 ,u5);
//流来计算
list.stream()
.filter((u)->{
return u.getAge()%2 == 0; })
.filter((u)->{
return u.getAge() > 23; })
.map((u)->{
return u.getName().toUpperCase();})
.sorted((o1,o2)->{
return o2.compareTo(o1);})
.limit(1)
.forEach(System.out::print);
}
}
并行执行任务,提高效率
特点
工作窃取
public class ForkJoinDemo extends RecursiveTask<Long> {
private Long start;
private Long end;
private Long temp = 10000L;
public ForkJoinDemo(Long start, Long end) {
this.start = start;
this.end = end;
}
public static void main(String[] args) {
}
@Override
protected Long compute() {
if ((end - start) < temp) {
Long sum = 0L;
for (Long i = start;i <= end;i++) {
sum += i;
}
return sum;
}
else {
long middle = (start + end) / 2;
ForkJoinDemo forkJoinDemo1 = new ForkJoinDemo(start, middle);
forkJoinDemo1.fork(); // 把任务压入线程队列
ForkJoinDemo forkJoinDemo2 = new ForkJoinDemo(middle + 1, end);
forkJoinDemo2.fork();
return forkJoinDemo1.join() + forkJoinDemo2.join();
}
}
}
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
test1();
test2();
test3();
// sum=500000000500000000时间4581
// sum=500000000500000000时间3855
// sum=500000000500000000时间141
}
public static void test1() {
long start = System.currentTimeMillis();
Long sum = 0L;
for (Long i = 1L;i <= 10_0000_0000;i++) {
sum += i;
}
long end = System.currentTimeMillis();
System.out.println("sum=" + sum + "时间" + (end - start));
}
public static void test2() throws ExecutionException, InterruptedException {
long start = System.currentTimeMillis();
ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinTask<Long> task = new ForkJoinDemo(0L, 10_0000_0000L);
ForkJoinTask<Long> submit = forkJoinPool.submit(task);
Long sum = submit.get();
long end = System.currentTimeMillis();
System.out.println("sum=" + sum + "时间" + (end - start));
}
public static void test3() {
long start = System.currentTimeMillis();
long sum = LongStream.rangeClosed(0L, 10_0000_0000L).parallel().reduce(0, Long::sum);
long end = System.currentTimeMillis();
System.out.println("sum=" + sum + "时间" + (end - start));
}
}
Java内存模型
关于JMM的同步的约定
1.线程解锁前必须把共享变量立刻刷回主存
2.线程加锁前必须读取主存中的最新值到工作内存中
3.加锁与解锁是同一把锁
八种操作
Read(读取):作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用;
load(载入):作用于工作内存的变量,它把read操作从主存中变量放入工作内存中;
Use(使用):作用于工作内存中的变量,它把工作内存中的变量传输给执行引擎,每当虚拟机遇到一个需要使用到变量的值,就会使用到这个指令;
assign(赋值):作用于工作内存中的变量,它把一个从执行引擎中接受到的值放入工作内存的变量副本中;
store(存储):作用于主内存中的变量,它把一个从工作内存中一个变量的值传送到主内存中,以便后续的write使用;
write(写入):作用于主内存中的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中;
lock(锁定):作用于主内存的变量,把一个变量标识为线程独占状态;
unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定;
相应规定
JMM对这8种操作给了相应的规定:
不允许read和load、store和write操作之一单独出现。即使用了read必须load,使用了store必须write
不允许线程丢弃他最近的assign操作,即工作变量的数据改变了之后,必须告知主存
不允许一个线程将没有assign的数据从工作内存同步回主内存
一个新的变量必须在主内存中诞生,不允许工作内存直接使用一个未被初始化的变量。就是对变量实施use、store操作之前,必须经过assign和load操作
一个变量同一时间只有一个线程能对其进行lock。多次lock后,必须执行相同次数的unlock才能解锁
如果对一个变量进行lock操作,会清空所有工作内存中此变量的值,在执行引擎使用这个变量前,必须重新load或assign操作初始化变量的值
如果一个变量没有被lock,就不能对其进行unlock操作。也不能unlock一个被其他线程锁住的变量
对一个变量进行unlock操作之前,必须把此变量同步回主内存
Volatile是Java虚拟机提供的轻量级同步机制
1.保证可见性
2.不保证原子性
3.禁止指令重排
保证可见性
public class JMMDemo {
private static volatile int num = 0;
public static void main(String[] args) {
new Thread(()->{
while (num == 0);
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
num = 1;
System.out.println(num);
}
}
不加volatile程序会死循环
不保证原子性
public class VDemo02 {
private volatile static int num = 0;
public static void add() {
num++;
}
public static void main(String[] args) {
for (int i = 1;i <= 20;i++) {
new Thread(()->{
for (int j = 0;j < 1000;j++) {
add();
}
}).start();
}
while (Thread.activeCount() > 2) {
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+" "+num);
}
}
如果不加lock与synchronized如何保证原子性
使用原子类
public class VDemo02 {
private volatile static AtomicInteger num = new AtomicInteger();
public static void add() {
num.getAndIncrement();
}
public static void main(String[] args) {
for (int i = 1;i <= 20;i++) {
new Thread(()->{
for (int j = 0;j < 1000;j++) {
add();
}
}).start();
}
while (Thread.activeCount() > 2) {
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+" "+num);
}
}
禁止指令重排
源代码=》编译器优化的重排=》指令并行也可能重排=》内存系统重排
volatile避免指令重排
内存屏障作用:
1.保证特定的操作的执行顺序
2.可以保证某些变量的内存可见性
饿汉式
// 饿汉式单例,可能会浪费空间
public class Hungry {
private Hungry() {
}
private final static Hungry HUNGRY = new Hungry();
public static Hungry getInstance() {
return HUNGRY;
}
}
懒汉式
// 懒汉式单例,单线程下可行,多线程并发
public class Lazy {
private Lazy() {
System.out.println(Thread.currentThread().getName()+" OK");
}
private volatile static Lazy LAZY;
// 双重检测锁模式的懒汉式单例
public static Lazy getInstance() {
if (LAZY == null) {
synchronized (Lazy.class) {
if (LAZY == null) {
LAZY = new Lazy(); // 不是原子性操作
/*
* 可能出现问题
* 1.分配内存空间
* 2.执行构造方法
* 3.把这个对象指向这个空间
*
* 若132执行 A
* B 此时Lazy还没有完成构造
* */
}
}
}
return LAZY;
}
public static void main(String[] args) {
for (int i = 0;i < 10;i++) {
new Thread(()->{
Lazy.getInstance();
}).start();
}
}
}
public class CASDemo {
// CAS:compareAndSet 比较再交换
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(2020);
// 如果期望的值达到了,那么就更新,否则不更新
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.get());
}
}
原理
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!weakCompareAndSetInt(o, offset, v, v + delta));
return v;
}
获取内存地址中的值为v,当内存地址值还是v,v更新为v+delta;自旋锁
CAS:比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么则执行操作,;否则循环(自旋锁)
缺点
1.自旋锁循环会浪费时间
2.一次性只能保证一个共享变量的原子性
3.ABA问题
带版本号的原子操作
public class CASDemo {
// CAS:compareAndSet 比较再交换
public static void main(String[] args) {
AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<Integer>(99, 1);
new Thread(()->{
int stamp = atomicStampedReference.getStamp(); // 获得版本号
System.out.println("A1=>"+stamp);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(atomicStampedReference.compareAndSet(99, 100,
atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
System.out.println("A2=>"+atomicStampedReference.getStamp());
System.out.println(atomicStampedReference.compareAndSet(100, 99,
atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
System.out.println("A3=>"+atomicStampedReference.getStamp());
},"A").start();
new Thread(()->{
int stamp = atomicStampedReference.getStamp(); // 获得版本号
System.out.println("B1=>"+stamp);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(atomicStampedReference.compareAndSet(99, 1,
stamp, stamp + 1));
System.out.println("B1=>"+atomicStampedReference.getStamp());
},"B").start();
}
}
公平锁,非公平锁
公平锁:先来后到
非公平锁:可以允许插队
可重入锁
递归锁
自旋锁
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!weakCompareAndSetInt(o, offset, v, v + delta));
return v;
}
public class DeadLockDemo {
public static void main(String[] args) {
String lockA = "lockA";
String lockB = "lockB";
new Thread(new MyThread(lockA,lockB),"thread1").start();
new Thread(new MyThread(lockB,lockA),"thread2").start();
}
}
class MyThread implements Runnable {
private String lockA;
private String lockB;
public MyThread(String lockA, String lockB) {
this.lockA = lockA;
this.lockB = lockB;
}
@Override
public void run() {
synchronized (lockA) {
System.out.println(Thread.currentThread().getName()+" lock:"+lockA+"=>"+lockB);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB) {
System.out.println(Thread.currentThread().getName()+" lock:"+lockB+"=>"+lockA);
}
}
}
}