java并发编程[持续更新]

[toc]

java并发编程

1.常用类介绍

Semaphore

Semaphore 类是一个计数信号量,必须由获取它的线程释放, 通常用于限制可以访问某些资源(物理或逻辑的)线程数目。

Semaphore包含三种操作

  1. 初始化

  2. 获取acquire()

  3. 释放 release()

当信号量大于0的时候semaphore会响应线程请求,释放资源,当信号量等于0时即阻塞线程。

Semaphore有两种模式,公平模式和非公平模式

公平模式遵循FIFO,按照acquire的顺序来分配资源,非公平则为抢占式的。

Semaphore的类图如下,使用内部类Sync继承AbstractQueuedSynchronizer实现

classDiagram Serializable <|-- Semaphore : implements Semaphore *-- Sync AbstractQueuedSynchronizer <|-- Sync Sync <|-- NonfairSync Sync <|-- FairSync class Semaphore{ Semaphore : -Sync sync Semaphore: +Semaphore(int permits) Semaphore: +Semaphore(int permits, boolean fair) Semaphore: +acquire() Semaphore: +acquire(int permits) Semaphore: +release() Semaphore: +release(int permits) } class Sync{ ... } class NonfairSync{ ... } class FairSync{ ... }

2.名词解释

2.1 线程安全

如果一个进程中有多个线程在同时运行同一段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

2.2 可重入锁和不可重入锁

可重入锁,指的是以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的。意义之一在于防止死锁*。

实现原理:每个锁关联一个请求计数器和占有他的线程,当计数为0时,锁未被占用,当线程请求占用锁时,jvm标记锁的占有者,且将请求计数器置为1。同一线程再次请求锁,计数器递增。每当占用线程退出同步块,计数器递减,知道计数器为0,锁被释放。

*:此处的防止死锁实例

public class demo {
    public synchronized void methodA(){
        methodB();
    }

    public synchronized void methodB(){
        //todo do something
    }
}

当一个线程调用demo类对象的methodA同步方法,如果demo类对象锁未被占有,该线程占有锁,此时调用methodA会触发methodB的调用,此时需要再获取一次锁,只有可重入可以实现。

如下,子类覆写了父类的synchonized方法,然后调用父类中的方法,此时如果没有可重入的锁,那么这段代码将产生死锁

public class Demo {
    int i = 10;

    public synchronized void parent() {
        i--;
        System.out.println("parent:" + i);
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static class Demo2 extends Demo {
        @Override
        public synchronized void parent() {
            try {
                while (i > 1) {
                    i--;
                    System.out.println("child:" + i);
                    Thread.sleep(100);
                    super.parent();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                Demo2 demo2 = new Demo2();
                demo2.parent();
            }
        });
        thread.start();
    }
}

synchronized和ReentrantLock都是可重入锁

原文地址:https://www.cnblogs.com/CodingJacob/p/12172381.html