Java中的信号量

信号量通过使用计数器控制对共享资源的访问。如果计数器大于零,则允许访问。如果为零,则拒绝访问。计数器计数的是允许访问共享资源的许可证。因此,要访问资源,必须从信号量向线程授予许可。

null

信号量的工作原理

通常,要使用信号量,希望访问共享资源的线程会尝试获取许可。

  • 如果信号量的计数大于零,那么线程将获取一个许可证,这将导致信号量的计数递减。
  • 否则,线程将被阻塞,直到获得许可证。
  • 当线程不再需要访问共享资源时,它会释放许可,这会导致信号量的计数增加。
  • 如果有另一个线程正在等待许可证,那么该线程将在那时获得许可证。

Java提供 信号灯 上课 JAVAutil。同时发生的 实现这种机制的包,因此您不必实现自己的信号量。

流程图: d

信号量类中的构造函数: 信号量类中有两个构造函数。

Semaphore(int num)
Semaphore(int num, boolean how)

在这里 号码 指定初始许可证计数。因此,它指定了一次可以访问共享资源的线程数。如果是一个,那么在任何时候只有一个线程可以访问该资源。默认情况下,所有等待的线程都以未定义的顺序被授予许可。通过设置 怎样 为了实现这一点,您可以确保等待线程按照请求访问的顺序获得许可。

使用信号量作为锁( 防止种族状况 )

我们可以使用信号量来锁定对资源的访问,每个想要使用该资源的线程必须首先调用 获得() 在访问资源以获取锁之前。当线程处理完资源后,它必须调用 释放() 释放锁。下面是一个例子来说明这一点:

// java program to demonstrate
// use of semaphores Locks
import java.util.concurrent.*;
//A shared resource/class.
class Shared
{
static int count = 0 ;
}
class MyThread extends Thread
{
Semaphore sem;
String threadName;
public MyThread(Semaphore sem, String threadName)
{
super (threadName);
this .sem = sem;
this .threadName = threadName;
}
@Override
public void run() {
// run by thread A
if ( this .getName().equals( "A" ))
{
System.out.println( "Starting " + threadName);
try
{
// First, get a permit.
System.out.println(threadName + " is waiting for a permit." );
// acquiring the lock
sem.acquire();
System.out.println(threadName + " gets a permit." );
// Now, accessing the shared resource.
// other waiting threads will wait, until this
// thread release the lock
for ( int i= 0 ; i < 5 ; i++)
{
Shared.count++;
System.out.println(threadName + ": " + Shared.count);
// Now, allowing a context switch -- if possible.
// for thread B to execute
Thread.sleep( 10 );
}
} catch (InterruptedException exc) {
System.out.println(exc);
}
// Release the permit.
System.out.println(threadName + " releases the permit." );
sem.release();
}
// run by thread B
else
{
System.out.println( "Starting " + threadName);
try
{
// First, get a permit.
System.out.println(threadName + " is waiting for a permit." );
// acquiring the lock
sem.acquire();
System.out.println(threadName + " gets a permit." );
// Now, accessing the shared resource.
// other waiting threads will wait, until this
// thread release the lock
for ( int i= 0 ; i < 5 ; i++)
{
Shared.count--;
System.out.println(threadName + ": " + Shared.count);
// Now, allowing a context switch -- if possible.
// for thread A to execute
Thread.sleep( 10 );
}
} catch (InterruptedException exc) {
System.out.println(exc);
}
// Release the permit.
System.out.println(threadName + " releases the permit." );
sem.release();
}
}
}
// Driver class
public class SemaphoreDemo
{
public static void main(String args[]) throws InterruptedException
{
// creating a Semaphore object
// with number of permits 1
Semaphore sem = new Semaphore( 1 );
// creating two threads with name A and B
// Note that thread A will increment the count
// and thread B will decrement the count
MyThread mt1 = new MyThread(sem, "A" );
MyThread mt2 = new MyThread(sem, "B" );
// stating threads A and B
mt1.start();
mt2.start();
// waiting for threads A and B
mt1.join();
mt2.join();
// count will always remain 0 after
// both threads will complete their execution
System.out.println( "count: " + Shared.count);
}
}


输出:

Starting A
Starting B
A is waiting for a permit.
B is waiting for a permit.
A gets a permit.
A: 1
A: 2
A: 3
A: 4
A: 5
A releases the permit.
B gets a permit.
B: 4
B: 3
B: 2
B: 1
B: 0
B releases the permit.
count: 0

注: 在上述程序的不同执行中,输出可能不同,但 计数 变量将始终保持为0。

以上项目说明:

  • 该程序使用信号量来控制对 计数 变量,它是共享类中的静态变量。 共享。计数 由线程A递增五倍,由线程B递减五倍。以防止这两个线程访问共享。同时,只有在从控制信号量获取许可证后才允许访问。进入完成后,许可证被发放。通过这种方式,一次只有一个线程将访问共享。计数,如输出所示。
  • 注意MyThread类中run()方法中对sleep()的调用。它用于“证明”对共享资源的访问。计数由信号量同步。在run()中,对sleep()的调用会导致调用线程在每次访问共享线程之间暂停。计数这通常会使第二个线程运行。但是,由于信号量的原因,第二个线程必须等到第一个线程释放了许可证,这只有在第一个线程完成所有访问之后才会发生。因此,分享。计数首先由线程A递增五倍,然后由线程B递减五倍。增量和减量在汇编代码中不混合。
  • 在不使用信号量的情况下,访问 共享。计数 这两个线程将同时发生,增量和减量将混合在一起。要确认这一点,请尝试对呼叫进行评论 获得() 释放() .当你运行该程序时,你会看到对共享资源的访问。计数不再同步,因此您不会始终获得 计数 值为0。

下一步: JAVAutil。同时发生的Java中的信号量类

本文由 高拉夫·米格拉尼 .如果你喜欢GeekSforgek,并想贡献自己的力量,你也可以使用 贡献极客。组织 或者把你的文章寄到contribute@geeksforgeeks.org.看到你的文章出现在Geeksforgeks主页上,并帮助其他极客。

如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写下评论。

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享