Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 任何不打';同步';关键词无处不在?_Java_Multithreading_Synchronization - Fatal编程技术网

Java 任何不打';同步';关键词无处不在?

Java 任何不打';同步';关键词无处不在?,java,multithreading,synchronization,Java,Multithreading,Synchronization,在我的java项目中,我编写的几乎所有非静态方法都是同步的。我决定今天修复一些代码,删除大部分synchronized关键字。就在那里,我创建了几个线程问题,这些问题花了相当长的时间才解决,性能没有提高。最后我恢复了一切 我没有看到任何人在编写代码时到处都是“同步的”。那么有什么理由我不应该让“同步””无处不在 如果我不太关心性能(即,该方法不会每隔几秒钟调用一次以上),该怎么办?只是它几乎肯定会减慢速度 每个同步对象都必须执行某种检查,以确保它尚未被使用,然后在使用时设置标志,并在完成时重置标

在我的java项目中,我编写的几乎所有非静态方法都是同步的。我决定今天修复一些代码,删除大部分
synchronized
关键字。就在那里,我创建了几个线程问题,这些问题花了相当长的时间才解决,性能没有提高。最后我恢复了一切

我没有看到任何人在编写代码时到处都是“
同步的”
。那么有什么理由我不应该让“
同步”
”无处不在


如果我不太关心性能(即,该方法不会每隔几秒钟调用一次以上),该怎么办?

只是它几乎肯定会减慢速度

每个同步对象都必须执行某种检查,以确保它尚未被使用,然后在使用时设置标志,并在完成时重置标志


这需要时间。您可能不会注意到功能的变化,但是,如果性能很重要,您需要注意。

当然-性能。监视器是有成本的

答案不是以随机方式删除或添加同步。最好阅读Brian Goetz的《实践中的Java并发性》或Doug Lea的《Java线程》之类的书,以了解如何正确地实现它。当然,还要好好学习新的并发包


多线程不仅仅是synchronized关键字。

性能点已经说明


另外,请记住,所有线程都会获得堆栈的不同副本。因此,如果一个方法只使用在该方法内部创建的变量,并且无法访问外部世界(例如,文件句柄、套接字、数据库连接等),那么就不可能出现线程问题

如果您不加选择地同步,您也有可能创建一个

假设我有两个类,
Foo
Bar
,它们都有一个同步方法
doSomething()
。进一步假设每个类都有一个同步方法,将另一个类的实例作为参数

public class Foo {

    synchronized void doSomething() {
        //code to doSomething
    }

    synchronized void doSomethingWithBar(Bar b) {
        b.doSomething();
    }

}

public class Bar {

    synchronized void doSomething() {
        //code to doSomething
    }

    synchronized void doSomethingWithFoo(Foo f) {
        f.doSomething();
    }
}
您可以看到,如果您有一个
Foo
实例和一个
Bar
实例,这两个实例都试图用*方法同时执行它们的
dosomething,则可能会发生死锁

要强制死锁,可以在
doSomethingWith*
方法中插入睡眠(以
Foo
为例):

在main方法中,启动两个线程以完成示例:

synchronized void doSomethingWithBar(Bar b) {
    try {
        Thread.sleep(10000);
    } catch (InterruptedException ie) {
        ie.printStackTrace();
    }

    b.doSomething();
}
public static void main(String[] args) {
    final Foo f = new Foo();
    final Bar b = new Bar();
    new Thread(new Runnable() {
        public void run() {
            f.doSomethingWithBar(b);
        }
    }).start();

    new Thread(new Runnable() {
        public void run() {
            b.doSomethingWithFoo(f);
        }
    }).start();
}

如果您认为将“synchronized”关键字放在任何地方都是一个很好的解决方案,甚至忽略了性能,那么您就不知道到底发生了什么,不应该使用它。我强烈建议在没有方向性地开始讨论之前先仔细阅读这个话题


线程是一个非常难掌握的主题,理解为什么要做这些事情非常重要。否则,您将得到许多代码,这些代码都是偶然产生的,而不是设计出来的。这只会给你带来痛苦

比将
synchronized
放在任何地方都要好得多的是仔细考虑类所需的不变量,然后进行足够的同步以确保这些不变量。如果过度同步,则会产生两种风险:

  • 死锁
  • 活性问题
  • 大家都知道。活跃度问题与同步的成本无关,而是与这样一个事实有关:如果在多线程应用程序中全局同步所有内容,那么许多线程将在等待获取监视器时被阻塞,因为另一个线程正在接触不相关的内容,但使用相同的监视器

    如果为了安全起见,您想在任何地方都添加关键字,那么我建议使用
    final
    而不是
    synchronized
    <代码>:)
    任何可以使
    final
    成为最终版本的东西都有助于更好的线程安全性,并且可以更容易地推断锁需要维护哪些不变量。举个例子,假设您有一个简单的类:

    public class SimpleClass {
        private volatile int min, max;
        private volatile Date startTime;
        // Assume there are many other class members
    
        public SimpleClass(final int min, final int max) {
            this.min = min;
            this.max = max;
        }
        public void setMin(final int min) {
            // set min and verify that min <= max
        }
        public void setMax(final int max) {
            // set max and verify that min <= max
        }
        public Date getStartTime() {
            return startTime;
        }
    }
    
    公共类SimpleClass{
    私有易失性最小值,最大值;
    私有可变日期起始时间;
    //假设还有许多其他的类成员
    公共SimpleClass(最终整数最小值,最终整数最大值){
    this.min=min;
    this.max=max;
    }
    公共无效设置最小值(最终整数最小值){
    
    //设置min并验证min假设您有这个示例

    
    synchronized (lock){
        doSomething();
    }
    
    如果您锁定了多个线程,则无法中断它们。最好使用锁定对象而不是“同步”,因为您可以更好地控制可能发生的中断。
    当然,与所有建议一样,“synchronized”也存在一些性能问题如果您过度使用它们,可能会出现死锁、活锁等。

    您不应该这样做,并且您可能需要重新考虑您的设计。根据我的经验,此级别的同步无法扩展。它可能会解决您眼前的问题,但无助于修复您的整个应用程序完整性

    例如:即使您有一个“已同步”的集合,一个线程可能希望一次性调用两个“已同步”方法,但不希望另一个线程看到中间结果。因此,细粒度“已同步”API的任何调用方都必须意识到这一点,这严重降低了该API的(程序员)可用性

    首先,最好使用工作线程。隔离特定的长时间运行的任务,以便单独的线程接受一个不可变的输入块,并且在完成时将结果排队到主线程的消息队列中(这当然应该是同步的)。如果没有其他事情可做,主线程可能轮询或明确等待信号。具体细节取决于您的性能要求和应用程序设计

    从长远来看,尝试理解数据库实现的ACID事务模型的实现