信号量(Semaphore)

      临界区同时最多只能有限定个数的线程可以进入!这是一个今天去naver china面试的时候被问到的面试题。 

      多线程的同步问题,首先宏观上要有一个抽象。就是多个线程之间可以共享内存,所以导致了两类问题thread interference 和 memory consistency errors.

信号量(Semaphore)_第1张图片

       当不同线程对同一个数据同时进行操作是,线程代码相互之间有干扰,最后很有可能会导致数据一致性的问题。第二个问题,就是一个线程对一个线程对数据的修改,另外一个线程不一定是可见的。这就是一个handle-before的问题。该问题可以先忽略,在官方文档里可以查阅。

       回到题目,现在我们来理解如何保证数据一致性的问题,对数据使用都是通过函数代码去操作的。所以对数据的保护其实就是对一段操作数据的代码块或者函数进行保护。

       这些被称为临界区的代码块就起到了数据一致性的保护。

package com.threadsyn;

import java.util.Random;

import static java.lang.Thread.sleep;

//该类保证只有最多mutex个线程会执行handle()函数里的实体;
public class ThreadSyn {
    private int mutex = 1;
    private int oriMutex = 1;

    public ThreadSyn(int mutex) {
        this.mutex = mutex;
        this.oriMutex = mutex;
    }

    public void handle(String str) throws InterruptedException {

        entry();

        int sec = new ThreadLocalRandom().current().nextInt(30) * 1000;

        sleep(sec);

        leave();
    }

    private void entry() throws InterruptedException {
        synchronized (this) {
            if (this.mutex <= 0) {
                this.wait();
                --this.mutex;
            } else {
                --this.mutex;
            }

            System.out.println("进入 临界区线程数 " + (this.oriMutex - this.mutex));
        }
    }

    private void leave() {
        synchronized (this) {
            this.mutex++;
            this.notify();
            System.out.println("离开 临界区线程数 " + (this.oriMutex - this.mutex));
        }
    }

}


不过上面这个答案是相当愚蠢的,其实整个题的核心回归到线程互斥和同步的问题上就是信号量的概念。在JAVA SE中是提供了信号量的支持。

package com.threadsyn;

import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadLocalRandom;

import static java.lang.Thread.sleep;

//该类保证只有最多mutex个线程会执行handle()函数里的实体;
public class ThreadSyn {
    private Semaphore semaphore;
    
    public ThreadSyn(int mutex) {
        this.semaphore = new Semaphore(mutex,true);
    }

    public void handle(String str) throws InterruptedException {

        this.semaphore.acquire();

        int sec = ThreadLocalRandom.current().nextInt(30) * 1000;

        sleep(sec);

        this.semaphore.release();
    }
    

}

        对于信号量是1968年Edsger Dijikstra发明的,作为同步原语。关于信号量有个需要注意的就是其他线程可以通过调用release释放许可。而且,许可不是必须由获取它的线程释放。

       其实在高并发的应用中,对多线程的处理问题考查是比较多的,所以建议还是看下《JAVA核心卷 Ⅰ》

你可能感兴趣的:(JAVA多线程)