并发学习笔记(三)——并发包(同步控制工具)

ReentrantLock(重入锁)

  • 可重入:单线程可以重复进入(次数),但要重复退出(相同次数)
public class TestReentrantLock implements Runnable {
    private static ReentrantLock lock = new ReentrantLock();
    private static int i = 0;

    @Override
    public void run() {
        for (int j = 0; j < 1000000; j++) {
            lock.lock();
            lock.lock();
            try {
                i++;
            } finally {
                lock.unlock();
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TestReentrantLock tl = new TestReentrantLock();
        Thread t1 = new Thread(tl);
        Thread t2 = new Thread(tl);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(i);
    }
}

单线程中,可重复进行lock()获得锁(内部记录次数),同样的需要执行相同次数unlock()。若lock>unlock,则线程结束后,其他线程无法获得锁从而阻塞;若lock<unlock,则会抛出IllegalMonitorStateException,监视器状态异常。

  • 可中断:lockInterruptibly()可中断式地加锁
public class TestReentrantLockInterrupt implements Runnable {
    private static ReentrantLock lock1 = new ReentrantLock();
    private static ReentrantLock lock2 = new ReentrantLock();
    private int lock;

    /**
     * 控制加锁顺序,方便构成死锁
     */
    public TestReentrantLockInterrupt(int lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        try {
            if (lock == 1) {
                // 可中断的加锁
                lock1.lockInterruptibly();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                }
                lock2.lockInterruptibly();
            } else {
                lock2.lockInterruptibly();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                }
                lock1.lockInterruptibly();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock1.isHeldByCurrentThread())
                lock1.unlock();
            if (lock2.isHeldByCurrentThread())
                lock2.unlock();
            System.out.println(Thread.currentThread().getId() + ":线程退出");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TestReentrantLockInterrupt tl1 = new TestReentrantLockInterrupt(1);
        TestReentrantLockInterrupt tl2 = new TestReentrantLockInterrupt(2);
        Thread t1 = new Thread(tl1);
        Thread t2 = new Thread(tl2);
        t1.start();
        t2.start();
        Thread.sleep(1000);
        DeadlockChecker.check();
    }
}

死锁检查类DeadlockChecker.java

public class DeadlockChecker {
    private static final ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
    final static Runnable deadlockCheck = new Runnable() {
        @Override
        public void run() {
            while (true) {
                long[] deadlockedThreadIds = mbean.findDeadlockedThreads();
                if (deadlockedThreadIds != null) {
                    ThreadInfo[] threadInfos = mbean.getThreadInfo(deadlockedThreadIds);
                    for (Thread t : Thread.getAllStackTraces().keySet()) {
                        for (ThreadInfo threadInfo : threadInfos) {
                            if (t.getId() == threadInfo.getThreadId()) {
                                t.interrupt();
                            }
                        }
                    }
                }
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                }
            }
        }
    };

    public static void check() {
        Thread t = new Thread(deadlockCheck);
        t.setDaemon(true);
        t.start();
    }
}

注:当线程1和线程2形成死锁(使用可中断的加锁)时,使用Interrupt发送中断信号,可以中断线程,进入Catch块。

  • 可限时:超时不能获得锁,就返回false,不会永久等待构成死锁。
public class TestReentrantLockTime implements Runnable {
    private static ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        try {
            if (lock.tryLock(5, TimeUnit.SECONDS)) {
                Thread.sleep(6000);
            } else {
                System.out.println("Get lock failed");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread())
                lock.unlock();
        }
    }

    public static void main(String[] args) {
        TestReentrantLockTime tl = new TestReentrantLockTime();
        Thread t1 = new Thread(tl);
        Thread t2 = new Thread(tl);
        t1.start();
        t2.start();
    }
}

注:线程1线程2都需要同一把锁,拿不到锁的线程超时就会返回false,进入else分支。

  • 公平锁:先来先得。若不是公平锁,则先申请锁的,不一定先拿到锁;反之,公平锁一定是先来先得。公平锁性能不如非公平锁,处理排队。
	// ReentrantLock的一个构造函数
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

Condition(条件)

SynchronizedObject.wait/Object.notify配合使用。
ConditaionReentrantLock配合使用。

public class TestReentrantLockCondition implements Runnable {
    public static ReentrantLock lock = new ReentrantLock();
    public static Condition condition = lock.newCondition();

    @Override
    public void run() {
        try {
            lock.lock();
            condition.await();
            System.out.println("Thread is going on");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread())
                lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TestReentrantLockCondition tl = new TestReentrantLockCondition();
        Thread t1 = new Thread(tl);
        t1.start();
        Thread.sleep(2000);
        // 通知线程t1继续运行
        lock.lock();
        condition.signal();
        lock.unlock();
    }
}

说明:(1)线程1拿到锁(2)线程1等待条件,暂时释放锁(3)主线程拿到锁(4)主线程通知条件(5)主线程释放锁(6)线程1拿到锁(多个线程需要竞争锁),继续运行。
注:Condition.awaitUninterruptibly(),不会响应中断标志,Object.wait()当遇到中断标记时,会抛出异常。

Semaphore(信号量)

共享锁,可以允许多个线程进入临界区(PV操作中的信号量),带容量的。

  • void acquire():阻塞式的请求信号量。
  • void acquireUninterruptibly():不可中断阻塞式的请求信号量。
  • boolean tryAcquire():非阻塞请求信号量,立马返回。
  • boolean tryAcquire(long timeout,TIneUnit unit):阻塞式限时请求信号量,超时或成功返回结果。
  • void release():释放信号量。
public class TestSemapDemo implements Runnable {
    private final Semaphore semp = new Semaphore(5);
    private AtomicInteger i = new AtomicInteger(0);

    @Override
    public void run() {
        try {
            semp.acquire();
            // 模拟耗时操作
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getId() + ":done " + i.incrementAndGet() + " !");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semp.release();
        }
    }

    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(20);
        final TestSemapDemo demo = new TestSemapDemo();
        for (int i = 0; i < 20; i++) {
            pool.submit(demo);
        }
    }
}

代码说明:初始化了容量为5的信号量,每次请求都会减少1个,释放增加一个(回忆PV操作的信号量即可)。

ReadWriteLock(读写锁)

ReadWriteLock是JDK5提供的读写分离锁。
读-读不互斥:读读之间不阻塞。
读-写互斥:读阻塞写,写也会阻塞读。
写-写互斥:写写阻塞。

非阻塞阻塞
阻塞阻塞
// 主要方法
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
ReentrantReadWriteLock.ReadLock  readLock = lock.readLock();
// 读写锁的方法和ReentrantLock一致.
// lock还可以获得读锁的数量,判断写是否被锁定等方法
// public int getReadLockCount()
// public boolean isWriteLocked()
// 拿到等待线程列表等
// 具体可看读写锁,和面用到在详细记录.

CountDownLatch(倒数计时器)

构造函数初始化一个数量,每次countDown,都会减1(CAS操作)。

public class TestCountDownLatch implements Runnable {
    static final CountDownLatch end = new CountDownLatch(10);
    static final TestCountDownLatch demo = new TestCountDownLatch();

    @Override
    public void run() {
        try {
            Thread.sleep(new Random().nextInt(10) * 1000);
            System.out.println("check complete!");
            end.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService threadPool = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            threadPool.submit(demo);
        }
        // 等待检查
        end.await();
        System.out.println("BOOM!");
        threadPool.shutdown();
    }
}

类似于方便的同步操作,先序任务完成后,后续线程才可以进行。

CyclicBarrier(循环栅栏)

Cyclic意为循环,也就是说栅栏可以重复使用。比如,设置为10,一批10个线程集合后,计数器归零,执行指定操作,然后进行下一轮集合。
构造函数:public CyclicBarrier(int parties, Runnable barrierAction),栅栏的大小和一次循环后需要执行的操作。

public class TestCyclicBarrier {
    public static class Soldier implements Runnable {
        private String soldier;
        private final CyclicBarrier barrier;

        Soldier(CyclicBarrier barrier, String name) {
            this.soldier = name;
            this.barrier = barrier;
        }

        @Override
        public void run() {
            try {
                barrier.await();
                doWork();
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
            }
        }

        private void doWork() {
            try {
                Thread.sleep(Math.abs(new Random().nextInt() % 10000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(soldier + "完成任务!");
        }
    }

    public static class BarrierRun implements Runnable {
        boolean flag;
        int N;

        public BarrierRun(boolean flag, int n) {
            this.flag = flag;
            N = n;
        }

        @Override
        public void run() {
            if (flag) {
                System.out.println("司令:士兵" + N + "个,任务完成!");
                flag = false;
            } else {
                System.out.println("司令:士兵" + N + "个,集合完毕!");
                flag = true;
            }
        }
    }

    public static void main(String[] args) {
        final int N = 10;
        Thread[] allSoldier = new Thread[N];
        boolean flag = false;
        CyclicBarrier barrier = new CyclicBarrier(N, new BarrierRun(flag, N));
        System.out.println("集合队伍!");
        for (int i = 0; i < N; i++) {
            System.out.println("士兵" + i + "报道");
            allSoldier[i] = new Thread(new Soldier(barrier, "士兵" + i));
            allSoldier[i].start();
            //if (i == 5) {
            //    allSoldier[0].interrupt();
            //}
        }
    }
}

10个士兵集合完毕,才可以执行任务,同步问题,用CyclicBarrier可以实现,且可以完成多组士兵集合执行任务。
(1)首先,士兵开始集合,进行await(),阻塞式的等待。
(2)10次后,激活Runnable任务,集合完毕。
(3)执行任务,进行await(),阻塞式的等待。
(4)10次后,激活Runnable任务,任务完成。
这个任务是可以中断的,当中断后抛出InterruptedException异常,而等待在该栅栏上的其他线程会抛出BrokenBarrierException异常(不会集合完成,没有意义的等待)。

LockSupport

提供线程阻塞原语。

  • LockSupport.park():挂起线程
  • LockSupport.unpark(t1):停止挂起线程
    与suspend()的区别:不容易引起线程冻结(resume发生在suspend前,后调用suspend造成永久性阻塞)。
    park是不会抛出异常的,但是会响应中断(Interrupt)标记。
    park后主要有两种方式可以继续运行,(1)Thread.unpark(t1)(2)t1.interrupt
public class TestLockSupport {
    private static final Object u = new Object();
    private static ChangeObjectThread t1 = new ChangeObjectThread("t1");
    private static ChangeObjectThread t2 = new ChangeObjectThread("t2");

    public static class ChangeObjectThread extends Thread {
        ChangeObjectThread(String name) {
            super.setName(name);
        }

        @Override
        public void run() {
            synchronized (u) {
                System.out.println("in " + getName());
                LockSupport.park();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        t1.start();
        t2.start();
        Thread.sleep(100);
//        t2.interrupt();
//        t1.interrupt();
        LockSupport.unpark(t1);
        LockSupport.unpark(t2);
        t1.join();
        t2.join();
    }
}

ReentrantLock的实现

(1)内部通过CAS状态判断是否修改成功。

// 非公平锁
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

比较和设置状态State,成功则拿到排他锁,立即返回。
(2)如果没拿到锁,线程就要进入等待队列,队列中的线程都要执行park

    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

源码中可以看到,最后没有拿到锁,队列中的线程需要去parkAndCheckInterrupt,也就是park去挂起。

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值