java - 如何实现信号量

标签 java multithreading semaphore

所以我创建了一个程序,试图显示使用共享变量的危险,所以我有 3 个类,主要称为 DangersOfSharedVariables 和一个 Incrementer减量器类。

因此,我们的想法是让两个线程同时运行,两个线程都调用各自受尊重的方法,因此 Decrementer 类将调用 main 和 main 中的 decrementShared() 方法Incrementer 类将调用 main 中的 incrementShared() 方法。

主要方法如下:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package dangersofsharedvariables;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 */
public class DangersOfSharedVariables {

    /**
     * @param args the command line arguments
     */
    private static int sharedValue =0;
    private static int numberOfCycles = 2000000000;

    public static void main(String[] args) {
        // TODO code application logic here
        Incrementer in = new Incrementer(numberOfCycles);
        Decrementer de = new Decrementer(numberOfCycles);
        Semaphore sem = new Semaphore(1);


        in.start();
        try {
            in.join();
        } catch (InterruptedException ex) {}
        de.start();
        try {
            de.join();
        } catch (InterruptedException ex) {}
        System.out.println(sharedValue);
    }

    public void decrementShared(){
        sharedValue -=10;
    }

    public void incrementShared(){
        sharedValue +=10;
    }

}

这是 Incrementer 类

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package dangersofsharedvariables;

/**
 *
 * 
 */
public class Incrementer extends Thread {

    private int numberOfIncrements;

    public Incrementer(int numberOfIncrements) {
        this.numberOfIncrements = numberOfIncrements;

    }

    @Override
    public void run() {
        DangersOfSharedVariables in = new   DangersOfSharedVariables();
        for(int i = 0; i < numberOfIncrements; i++){
            in.incrementShared();
        }
    }
}

减量器类:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package dangersofsharedvariables;

/**
 *
 * 
 */
public class Decrementer extends Thread {
    private int numberOfDecrements;
    public Decrementer(int numberOfDecrements){
        this.numberOfDecrements = numberOfDecrements;

    }

    @Override
    public void run(){
        DangersOfSharedVariables d = new DangersOfSharedVariables();
        for(int i = 0; i < numberOfDecrements; i++){
            d.decrementShared();
        }
    }
}

我在谷歌上搜索,更安全的方法是使用 Sempaphore 类。因此,我自己尝试使用我找到的信号量模板,但不确定如何实现它。

信号量类:

package dangersofsharedvariables;

public class Semaphore {

    // *************************************************************
    // Class properties.
    // Allow for both counting or mutex semaphores.
    private int count;

    // *************************************************************
    // Constructor
    public Semaphore(int n) {
        count = n;
    }

    // *************************************************************
    // Public class methods.
    // Only the standard up and down operators are allowed.
    public synchronized void down() {

        while (count == 0) {

            try {
                wait(); // Blocking call.
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            }
        }
        count--;
    }

    public synchronized void up() {
        count++;
        notify();
    }

}

最佳答案

根据您的询问,以下是有关信号量数据结构的简要说明。信号量可用于解决各种同步问题。这个概念是由 Dijkstra(1968)提出的,他引入了信号量作为操作系统一部分的想法,以便进程之间以及进程与硬件之间的同步。

典型信号量的结构涉及 4 个阶段:

  1. 非关键区域
  2. 进入协议(protocol)
  3. 关键区域
  4. 退出协议(protocol)

非关键区域是可以由 2-n 个线程同时执行的任何代码。

进入协议(protocol)是进程在进入临界区之前必须执行的代码。它的目的是在另一个进程已经使用共享资源的情况下防止该进程进入临界区域。

临界区是访问共享资源的代码部分。

退出协议(protocol)是进程在完成其临界区域后必须立即执行的代码。

信号量可以有不同的用途:

  1. 用于对单个共享资源的互斥访问,在这种情况下,信号量称为二进制信号量
  2. 保护对资源多个实例的访问(计数信号量)
  3. 同步两个进程(阻塞信号量)

信号量机制的多功能性是通过正确的初始化来实现的。

出于演示目的,请参阅下面的示例,其中展示了最简单的二进制信号量实现:

信号量:

package BinarySemaphore;

public class Semaphore{
    private static Semaphore semaphore;
    private static int resource = 1;

    private Semaphore(){}

    public synchronized void increment(){
        while(isAvailable()){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        resource += 1;

        report();

        this.notifyAll();
    }

    public synchronized void decrement(){
        while(!isAvailable()){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        resource -= 1;

        report();

        this.notifyAll();
    }

    public synchronized final static boolean isAvailable(){
        return resource == 1 ? true : false;
    }

    public synchronized final static void report(){
        System.out.println("Resource value: " + resource);
    }

    public final static Semaphore getInstance(){
        if(semaphore == null){
            semaphore = new Semaphore();
        }
        return semaphore;
    }
}

增量器:

package semaphore;

import BinarySemaphore.Semaphore;

public class Incrementer implements Runnable{
    private static Semaphore semaphore = null;

public Incrementer(Semaphore s){
    semaphore = s;
}

@Override
public void run() {
    for(int i = 0; i < 10; i++){
        System.out.println("Incrementing...");
        semaphore.increment();
    }
}

}

减量器:

package semaphore;

import BinarySemaphore.Semaphore;

public class Decrementer implements Runnable{
    private static Semaphore semaphore = null;

    public Decrementer(Semaphore s) {
        semaphore = s;
    }

    @Override
    public void run() {
        for(int i = 0; i < 10; i++){
            System.out.println("Decrementing...");
            semaphore.decrement();
        }
    }
}

主要:

package semaphore;

import BinarySemaphore.Semaphore;

public class Main {
    public static void main(String[] args){
        Thread iIncrement = new Thread(new Incrementer(Semaphore.getInstance()));
        Thread iDecrement = new Thread(new Decrementer(Semaphore.getInstance()));

        iIncrement.start();
        iDecrement.start();
    }
}

输出:

Decrementing...
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Decrementing...
Resource value: 1
Incrementing...
Resource value: 0
Resource value: 1

关于java - 如何实现信号量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33766797/

相关文章:

c# - 多线程进程中静态 Queue.Enqueue 期间意外数据丢失

c - 在c中用信号量同步两个子进程

c - 生产者/消费者解决方案

java - 将 JMenuItem 添加到已经可见的 JMenu

java - 在developer.android.com 网站上哪里可以找到教程的源代码?

java - tomcat中的UncaughtExceptionHandler

java - 具有等待/通知的生产者消费者代码不适用于第二个产品

.net - 是否有必要在信号量上调用 Dispose?

java - 使用 OpenCV 和 JavaCV 捕获具有间隔的帧

Java刷新第二种形式