多线程共享资源的同步是更好的选择吗?

时间:2015-05-10 17:19:12

标签: java multithreading synchronized

public class MyResource {

private int count = 0;

void increment() {

    count++;

}

void insert() {    // incrementing shared resource count
    for (int i = 0; i < 100000000; i++) {
        increment();
    }

}

void insert1() {       //incrementing shared resource count
    for (int i = 0; i < 100000000; i++) {
        increment();
    }

}

void startThread() {

    Thread t1 = new Thread(new Runnable() {  //thread incrementing count using insert()

        @Override
        public void run() {
            insert();
        }
    });

    Thread t2 = new Thread(new Runnable() {    //thread incrementing count using insert1()

        @Override
        public void run() {
            insert1();
        }
    });

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

    try {
        t1.join(); //t1 and t2 race to increment count by telling current thread to wait
        t2.join();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

void entry() {
    long start = System.currentTimeMillis();
    startThread();            //commenting insert(); insert1() gives output as time taken = 452(approx)   110318544  (obvious)

    // insert(); insert1();     //commenting startThread() gives output as time taken = 452(approx)   200000000

    long end = System.currentTimeMillis();
    long time = end - start;
    System.out.println("time taken = " + time);

    System.out.println(count);
}

}

程序入口点来自entry()方法。

1.仅使用insert(); insert1(); (正常方法调用)和注释startThread()(执行线程)给出了代码中显示的结果。

2.现在评论插入(); insert1();并使用startThread()(执行线程)给出结果,如代码所示。

3.现在我同步increment()给出输出时间= 35738 200000000

如上所述,同步可以避免访问共享资源,但另一方面需要花费大量时间来处理。

那么,如果它会降低性能会对同步有什么用呢?

2 个答案:

答案 0 :(得分:0)

您不应该使用同步来提高性能,您可以使用它来保护共享资源。 这是一个真实的代码示例吗?因为如果你想在这里使用线程来分割工作同步

increment() 

不是最好的方法......

修改

here所述,您可以更改此特定代码的设计,以便更有效地划分2个线程之间的工作。 我改变了他们的例子以满足你的需要,但那里描述的所有方法都很好。

import java.util.*;
import java.util.concurrent.*;
import static java.util.Arrays.asList;

public class Sums {

    static class Counter implements Callable<Long> {

        private final long _limit;
        Counter(long limit) {
            _limit = limit;
        }

        @Override
        public Long call() {
            long counter = 0;
            for (long i = 0; i <= _limit; i++) {
                counter++
            }
            return counter;
        }                
    }

    public static void main(String[] args) throws Exception {

        int counter = 0;
        ExecutorService executor = Executors.newFixedThreadPool(2);
        List <Future<Long>> results = executor.invokeAll(asList(
            new Counter(500000), new Counter(500000));
        ));
        executor.shutdown();

        for (Future<Long> result : results) {
            counter += result.get();
        }                
    }    
}

如果你必须使用同步,AtomicLong会做得更好。

答案 1 :(得分:0)

表现不是唯一的因素。正确性也很重要。这是另一个问题,其中包含关键字synchronized的一些低级详细信息。

如果您正在寻找性能,请考虑使用java.util.concurrent.atomic.AtomicLong类。它已针对快速原子访问进行了优化。

编辑:

Synchonized在这个用例中是过度的。同步对于FileIO或NetworkIO更有用,其中调用更长并且正确性更重要。以下是AtomicLong的源代码。之所以选择易失性,是因为对于改变共享内存的短调用它的性能要高得多。

添加一个synchronized关键字会增加额外的java字节码,它会检查正确的状态以安全地获取锁定。易失性会将数据放入主内存中,这需要更长时间才能访问,但CPU强制执行原子访问,而不是生成额外代码的jvm。