java中的同步方法如何保证对对象没有干扰

时间:2017-07-20 19:00:28

标签: java multithreading synchronized

我想确保(我理解正确)并且知道java中的同步方法如何保证对对象没有干扰。

例如我有这段代码:

private void update_curr_mat(int stock_ind, double price, double time)
{
    synchronized(current_mat_data)
    {
        current_mat_data[stock_ind][HIGH_PRICE_IND] = price;
        current_mat_data[stock_ind][LOW_PRICE_IND] = price;
        current_mat_data[stock_ind][CLOSE_IND] = price;
        current_mat_data[stock_ind][HIGHEST_IND] = price;
        current_mat_data[stock_ind][LOWEST_IND] = price;

        current_mat_data[stock_ind][CURR_TIME_IND] = time;
    }
}

在这个例子中很明显,current_mat_data是同步的,当调用该方法时,另一个线程不能写入current_mat_data对象。

在这个例子中:

private synchronized void update_curr_mat(int stock_ind, double price, double time)
{
        current_mat_data[stock_ind][HIGH_PRICE_IND] = price;
        current_mat_data[stock_ind][LOW_PRICE_IND] = price;
        current_mat_data[stock_ind][CLOSE_IND] = price;
        current_mat_data[stock_ind][HIGHEST_IND] = price;
        current_mat_data[stock_ind][LOWEST_IND] = price;

        current_mat_data[stock_ind][CURR_TIME_IND] = time;
}

synchronized在方法定义中完成。我知道它保证了两个线程不能同时调用这个方法。

所以我的问题是,当第二个exmaple中的函数被调用时,可以保证其他线程无法访问对象current_mat_data吗?如果是真的,你能解释它是如何工作的吗?如果我对我写的东西不对,或者有些东西不清楚,请告诉我。

4 个答案:

答案 0 :(得分:2)

两个示例中,没有绝对的保证(只给出您已经显示的内容),没有任何东西可以编辑对象。也就是说,这句话

  

在这个例子中很明显,current_mat_data是同步的,当调用该方法时,另一个线程不能写入current_mat_data对象。

不正确。

唯一的保证是没有两个线程可以同时保持相同的锁;并且线程必须持有适当的锁来执行同步的块或方法(因此,如果另一个线程持有锁,则线程必须等到它变为可用才能获取锁并进入块或方法)。

你必须使用封装和良好的编程来构建任何额外的保证。

可能会让人感到困惑的是,每个对象都可以用作锁定,但您不必持有对象的锁来编辑该对象。也就是说,Java并不要求你拥有锁来编辑对象。要强制执行此类规则,您需要将对象编辑的每种方式都包含在使用该对象作为锁定的同步块或方法中。

两个示例之间的区别仅在于将哪个对象用作锁。第一个示例使用current_mat_data引用的对象;第二个使用this引用的对象(调用update_cur_mat方法的对象实例)。 (静态方法将使用类对象。)

答案 1 :(得分:1)

据我所知,不,虽然可能阻止其他线程调用update_curr_mat,但它仍然可以访问操作update_curr_mat对象的另一个非同步方法。例如,如果您有另一种方法:

public void mess_with_curr_mat(int stock_ind, double price)
{ 
    current_mat_data[stock_ind][HIGH_PRICE_IND] = price;
}

另一个线程可以调用此方法,没有任何东西阻止它这样做,因为它没有同步。但是,如果您要使update_curr_mat方法为static,并且current_mat_data变量也是静态的,那么您将避免这种风险,因为这会在实际的类对象本身上同步。

答案 2 :(得分:1)

  

在这个例子中很明显,current_mat_data是同步的,当调用该方法时,另一个线程不能写入current_mat_data对象。

错误。放synchronized(someObject) 会阻止任何其他帖子对someObject执行某些操作。

此处唯一发生的事情是只有一个主题输入 受保护的块!这是一种锁定代码段的方法。不是锁定那个对象的方法!

换句话说:假设update_curr_mat()是更新该对象的唯一方法 - 那么是,这个synchronized语句有效地阻止多个线程从篡改current_mat_dat

再次说明:您无法通过这种方式锁定对象进行更新。防止并行更改的唯一方法是确保修改该对象的每行和任何代码行都由同一个锁保护。

答案 3 :(得分:0)

Java synchronized不保证任何线程安全,这是您作为程序员的工作。它保证的是,任何时候两个线程都不能同时进入具有相同锁定对象的synchronized块。

所以如果你有:

final Object myLock = new Object();

void funcA() {
  synchronized(myLock) { 
    // ... 
  }
}

void funcB() {
  synchronized(myLock) { 
    // ... 
  }
}

然后在任何情况下线程都不能在funcA的同步块中,而另一个线程在funcB的同步块中,任何两个线程也不能在{{1}的同一块中或} funcA同时。

如果你有这样的代码:

funcB

然后仍然如此,但当然一个线程可以有final Object myLockA = new Object(); final Object myLockB = new Object(); void funcA() { synchronized(myLockA) { // ... } } void funcB() { synchronized(myLockB) { // ... } } 而另一个线程同时有myLockA。这是否是一件好事完全取决于同步块内的代码。

拥有单个锁定对象选项的原因是,您可以对哪些代码块需要具有独占访问权限进行细粒度控制。如果在上面的示例中myLockB写入与funcA完全不同的对象,则在访问其中一个时,没有理由将线程锁定在其他函数之外。