java并发编程艺术笔记

1. 并发编程遇到的挑战


多线程 减少上下文切换的方式:

  • 无锁并发编程:多线程竞争锁的时候会引起上下文的切换,在多线程处理数据的时候可以使用一些方法来避免使用锁;如将id按照hash算法取模分段,不同的线程处理不同段的数据
  • cas算法,
  • 使用最少的线程。避免创建太多不必要的线程,可以减少上下文切换
  • 协成:使用单线程实现多任务的调度,在单线程中维持多个任务间的切换

避免多个线程出现死锁

  • 避免一个线程同时获取多个锁
  • 避免一个线程在锁内同时占用多个锁,尽量保证一个锁占用一个资源
  • 尝试使用定时锁,使用lock.tryLock(timeout) 来代替使用内部锁机制
  • 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败
public class DeadLockDemo {

    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();


    public static void main(String[] args) {
        new DeadLockDemo().deadlock();
    }


    private void deadlock() {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock1) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    synchronized (lock2) {
                        System.out.println("thread 1 running");
                    }
                }
            }
        }, "thread==>1");
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock2) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    synchronized (lock1) {
                        System.out.println("thread 2 running");
                    }
                }
            }
        }, "thread==>2");
        thread1.start();
        thread2.start();
    }

}

2. Java并发机制的底层实现原理


Java CAS的原理:

CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当旧的预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。这其实就是一个乐观锁

synchronized 同步表现形式:

  • 对于普通的同步方法,锁是当前实例对象
  • 对于静态同步方法,锁是当前类的class对象
  • 对于同步方法块,锁是synchronized括号里面的对象

锁的类型有四种状态,由低到高:无锁状态,偏向锁,轻量级锁,重量级锁。锁的状态可以升级,但是不能降级

参考:https://www.cnblogs.com/paddix/p/5405678.html

状态之间的转换


10564585-d3250783f21d4cfe.png
image.png

3. Java 内存模型


Java内存模型的抽象结构

10564585-884e44beda1aa182.png
image.png

volatile 的特性

可见性:对于一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入
原子性:对任意单个volatile变量的读、写具有原子性,但是类似于volatile++这种复合操作不具备原子性

volatile 的写-读的内存语义

10564585-affd97154afa1369.png
image.png
  • volatile写的内存语义:当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存。


    10564585-c67167d3281982a9.png
    image.png
  • volatile读内存的语义:当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量

10564585-6cc675cb8a601c83.png
image.png

锁的释放和获取的内存语义

  • 当线程释放锁的时候,JMM会把线程对应的本地内存中的共享变量刷新到主内存中。


    10564585-4d6188a2c23f621b.png
  • 当线程获取锁的时候,JMM会把该线程对应的本地内存置为无效。


    10564585-e20f9ec023fbfa12.png
    image.png

猜你喜欢

转载自blog.csdn.net/weixin_34221112/article/details/87574923