用Java编写互斥体

用Java编写互斥体,java,multithreading,mutual-exclusion,Java,Multithreading,Mutual Exclusion,我是计算机科学的新手,正在读一本介绍线程和互斥体的书。我曾经尝试过用Java编写一个互斥体,它似乎大部分时间都能正常工作,但有时却不行 在我的代码中,critical部分将数字1到10添加到静态变量j中,结果是55(如果j从0开始)。如果我在临界区同时运行三个线程,我会得到j的随机最终值,这是有意义的 但是使用下面的互斥锁,大多数时候我会得到一个最终的j值165(55*3),这是我想要的,但是有时候,我会得到随机的j值。有人能看看我的代码,看看是怎么回事吗?谢谢 public class Myt

我是计算机科学的新手,正在读一本介绍线程和互斥体的书。我曾经尝试过用Java编写一个互斥体,它似乎大部分时间都能正常工作,但有时却不行

在我的代码中,critical部分将数字1到10添加到静态变量j中,结果是55(如果j从0开始)。如果我在临界区同时运行三个线程,我会得到j的随机最终值,这是有意义的

但是使用下面的互斥锁,大多数时候我会得到一个最终的j值165(55*3),这是我想要的,但是有时候,我会得到随机的j值。有人能看看我的代码,看看是怎么回事吗?谢谢

public class Mythread extends Thread {

    private static int j = 0;
    private static int mutex = 0;  // Initial value of the mutex is 0;

    @Override
    public void run() {


        while (test_and_set(mutex) == 1) {

            // wait here if mutex is 1
            System.out.println("Thread waiting..");
        } 

        for (int i = 1; i <= 10; i++) { // Start of Critical section 
            j += i;                     // 

        }
        System.out.println(j);       // End of Critical section 
                                     // Should add on 55 to j if one thread is running through the CS

       mutex = 0; // Thread that has finished the CS sets the mutex to 0.

    }

    public static int test_and_set(int oldMutexValue) {
        if (mutex == 0) {
            mutex = 1;
        }
        return oldMutexValue;
    }


}

public class Test1 {




    public static void main(String[] args) {

        Mythread thread1 = new Mythread();
        Mythread thread2 = new Mythread();
        Mythread thread3 = new Mythread();
        thread1.start();
        thread2.start();
        thread3.start();

    }



}
公共类Mythread扩展线程{
私有静态int j=0;
private static int mutex=0;//互斥的初始值为0;
@凌驾
公开募捐{
while(测试_和_集(互斥)==1){
//如果互斥量为1,请在此处等待
System.out.println(“线程等待…”);
} 

对于(int i=1;i,您的任务有java.util.concurrency.Semaphore类:

package test;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class MyThread extends Thread {
    private static int j = 0;
    private static final Semaphore mutex = new Semaphore(1, true);

    @Override
    public void run() {
        try {
            while (!mutex.tryAcquire(100, TimeUnit.MILLISECONDS)) {
                System.out.println("Thread waiting.");
            }
        }
        catch (InterruptedException e) {
            System.out.println("Thread interrupted.");
            return;
        }

        try {
            for (int i = 1; i <= 10; i++) { // Start of Critical section
                j += i;                     //

            }
            System.out.println(j);       // End of Critical section
            // Should add on 55 to j if one thread is running through the CS
        }
        finally {
            mutex.release(); // Thread that has finished the CS sets the mutex to 0.
        }
    }
}
封装测试;
导入java.util.concurrent.Semaphore;
导入java.util.concurrent.TimeUnit;
公共类MyThread扩展线程{
私有静态int j=0;
私有静态最终信号量互斥=新信号量(1,true);
@凌驾
公开募捐{
试一试{
而(!mutex.tryAcquire(100,时间单位.毫秒)){
System.out.println(“线程等待”);
}
}
捕捉(中断异常e){
System.out.println(“线程中断”);
返回;
}
试一试{

对于(int i=1;i),您创建了<强>竞争条件,使用<强>旋转锁。在java中不建议使用旋转锁。请考虑以下内容:

public class MyThread extends Thread {
private static int j = 0;

public void run() {
    synchronized(this) {
        for (int i = 1; i <= 10; i++) {
            j += i;
        }
    }
    System.out.println(j);
}
一个线程开始执行,另两个线程等待。另外两个线程等待。另外两个线程现在都同时设置互斥量并开始执行,给你一个奇数J值,因为它们都在同时改变它

要修复:

实现Javasynchronized方法。synchronized是Java处理线程安全和控制的内部方法。没有旋转锁

将您的MyThread更改为以下内容:

public class MyThread extends Thread {
private static int j = 0;

public void run() {
    synchronized(this) {
        for (int i = 1; i <= 10; i++) {
            j += i;
        }
    }
    System.out.println(j);
}
公共类MyThread扩展线程{
私有静态int j=0;
公开募捐{
已同步(此){
对于(int i=1;i(1)您的test_和_set()函数看起来应该模拟在许多计算机体系结构中实现的同名硬件指令。但是test_和_set()应该返回什么?提示:它应该告诉调用方调用方是否“赢得”互斥锁

(2) 你的test_和_set()有一个更大的问题:它不是原子的。如果你想知道为什么一台有“test”指令和“set”指令的计算机也需要有test_和_set(也称为TAS)指令,那是因为TAS指令是原子的。我猜你需要了解更多关于这意味着什么(见下面的4)

(3) TAS是古老的。现代计算机实现了一种更强大的称为比较和交换或比较和设置(CAS)的功能。如果你想了解现代同步算法的工作原理,你应该使用CAS而不是TAS

Java标准库有一个真正的原子CAS函数,您可以调用它:Java.util.concurrent.atomic.AtomicInteger.CompareAndSet(…)

(4) 在您有更多的使用经验之前,您可能不应该尝试学习如何编写同步函数/对象。让您感到遗憾的是,您没有同步您的test_和_set()函数。如果您不知道怎么做,那么您就没有太多编写多线程代码的经验


首先学习如何使用同步对象。然后你可以担心它们是如何实现的。

你的关键部分不受任何同步的保护。@MarkW
volatile
测试和设置
中没有帮助。动作不是原子的。很好@SotiriosDelimanolis@SotiriosDelimanolis你能解释一下你的意思吗n通过同步?我对这一点很陌生。编辑:事实上,这在我的书后面会介绍,所以我会继续读下去!阅读比赛条件。回答得好,但不是针对OP提出的问题。OP不想使用
同步
:他/她正试图通过编写自己的版本来学习
同步
的工作原理当然。
synchronized(这个)
在这里实际上没有帮助。多个线程需要在一个单一的共享对象上进行同步。我喜欢在引擎盖下实现细节的提示!特别高兴看到这个答案,因为OP显然是在问这个问题,哈哈。