有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

多线程如何在Java中为对象的不同成员拥有不同的同步块

我试图理解java中的同步块

在C/C++中,我们使用互斥来保护关键部分。所以,如果一个对象有两个资源,比如i和j,如果有两个接口SetI和SetJ分别修改i和j,我会声明两个互斥体,每个互斥体保护i和j,很简单

现在我正试图用java模拟同样的事情

考虑一个进入同步(OBJ)的线程,并希望修改它的成员I.P/P>

那么,我可以不让另一个线程进入一个不同的同步块,但属于同一个对象,它需要修改obj的另一个名为j的成员吗

我附上了一个示例代码,它试图执行上述任务,但只有一个线程获得了机会,而另一个想要修改其他变量的线程从未获得机会

如果要保护的资源是对象,我会对成员本身i和j进行同步。但由于这些是原始数据类型,我无法在同步中使用它们(我尝试了,但出现了编译错误)。因此,我被迫在“this”上同步

问题不在于我理解为什么只有一个线程有机会执行。相反,我如何实现我的需求,即“两个线程修改一个对象的两个不同资源不应该相互阻塞”

class object
{
    private boolean i;
    private boolean j;

    public void flipi(String arg)
    {
        synchronized(this)
        {
            while(true)
            {
                i = !i;
                System.out.println("flipi "+ "thread: " + arg + " value of i: " + i);
                try
                {
                    Thread.sleep(2000);
                }
                catch(Exception e)
                {
                    System.out.println(e);
                }
            }
        }
    }

    public void flipj(String arg)
    {
        synchronized(this)
        {
            while(true)
            {
                j = !j;
                System.out.println("flipj "+ "thread: " + arg + " value of j: " + j );
                try
                {
                    Thread.sleep(2000);
                }
                catch(Exception e)
                {
                    System.out.println(e);
                }
            }
        }
    }
}

class test extends Thread
{
    object obj;

    test(object obj)
    {
        this.obj = obj;
    }

    @Override
    public void run()
    {
        String threadname = Thread.currentThread().getName();

        if(threadname.equals("test1"))
        {
            obj.flipi(Thread.currentThread().getName());
        }
        else if(threadname.equals("test2"))
        {
            obj.flipj(Thread.currentThread().getName());
        }
    }
}

public class testsynchronized
{
    public static void main(String[] args)
    {
        object obj = new object();

        test t1 = new test(obj);
        test t2 = new test(obj);

        t1.setName("test1");
        t2.setName("test2");

        t1.start();
        t2.start();
    }
}

输出:

$ java testsynchronized
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true
flipj thread: test2 value of j: false
flipj thread: test2 value of j: true

共 (3) 个答案

  1. # 1 楼答案

    您可以创建两个不同的锁定对象并在其上同步,而不是在“this”上同步:

    class object
    {
        private boolean i;
        private boolean j;
        Object lock1 = new Object();
        Object lock2 = new Object();
    
        public void flipi(String arg)
        {
            synchronized(lock1)
            {
                while(true)
                {
                    i = !i;
                    System.out.println("flipi "+ "thread: " + arg + " value of i: " + i);
                    try
                    {
                        Thread.sleep(2000);
                    }
                    catch(Exception e)
                    {
                        System.out.println(e);
                    }
                }
            }
        }
    
        public void flipj(String arg)
        {
            synchronized(lock2)
            {
                while(true)
                {
                    j = !j;
                    System.out.println("flipj "+ "thread: " + arg + " value of j: " + j );
                    try
                    {
                        Thread.sleep(2000);
                    }
                    catch(Exception e)
                    {
                        System.out.println(e);
                    }
                }
            }
        }
    }
    
    class test extends Thread
    {
        object obj;
    
        test(object obj)
        {
            this.obj = obj;
        }
    
        @Override
        public void run()
        {
            String threadname = Thread.currentThread().getName();
    
            if(threadname.equals("test1"))
            {
                obj.flipi(Thread.currentThread().getName());
            }
            else if(threadname.equals("test2"))
            {
                obj.flipj(Thread.currentThread().getName());
            }
        }
    }
    
    public class testsynchronized
    {
        public static void main(String[] args)
        {
            object obj = new object();
    
            test t1 = new test(obj);
            test t2 = new test(obj);
    
            t1.setName("test1");
            t2.setName("test2");
    
            t1.start();
            t2.start();
        }
    }
    
  2. # 2 楼答案

    在同步块中有一个无限循环,它们都在同一个对象上同步(this)。一旦一个线程进入,它就永远不会离开,因此其他线程都不能进入同步块

    要允许不同线程在不相互干扰的情况下更新不同的变量,请在不同的事情上同步这些变量的更新:

    private final Object iGuard = new Object();
    private final Object jGuard = new Object();
    

    然后:

    synchronized (iGuard) { i = !i; }
    

    synchronized (jGuard) { j = !j; }
    

    顺便说一句,在线程名上切换行为基本上从来都不是正确的做法。只需创建如下线程:

    Thread t1 = new Thread(a -> a.flipi("Thread 1"));
    Thread t2 = new Thread(a -> a.flipj("Thread 2"));
    
    t1.start();
    t2.start();
    
  3. # 3 楼答案

    你可以看到

    while(true)
    

    正在为调用flipi("threadName")的run()方法运行 也就是说它从不打电话

     else if(threadname.equals("test2"))
    

    只有第一个flipi方法在循环中运行

    要理解这一点,请尝试其他方法,而不是进入无限循环