如何在Java中为不同的Object成员创建不同的同步块

时间:2018-03-27 06:26:13

标签: java multithreading

我正在尝试理解java中的synchronized块。

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

现在我试图在java中模拟相同的东西。

考虑进入synchronized(obj)并想要修改其成员i的线程。

然后,我可以没有另一个线程进入不同的同步块但是同一个对象,需要修改obj的其他成员名为j?

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

如果要保护的资源是对象,我将对成员本身进行同步,i和j。但由于这些是原始数据类型,我不能在synchronized中使用它们(我试过,但得到了编译错误)。所以,我被迫同步“这个”。

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

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 个答案:

答案 0 :(得分:1)

在同步块中有一个无限循环,它们都在同一个事物上同步(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();

答案 1 :(得分:1)

而不是同步'这个'您可以创建2个不同的锁定对象并对其进行同步:

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 :(得分:0)

你可以看到,

while(true)

正在运行调用flipi("threadName")的run()方法 这意味着它从不打电话

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

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

要理解相同的事情,除了进入无限循环

之外,尝试别的东西