package threadShareResource1;
public class NonSynchro1 {
private int sum = 0;
public static void main(String[] args) {
NonSynchro1 n = new NonSynchro1();
n.task();
System.out.println(n.getSum());
}
public synchronized void sumAddOne(){
sum++;
}
public void task(){
for (int i = 0; i < 100; i++) {
new Thread(new Runnable(){
@Override
public void run() {
sumAddOne();
}
}).start();
/* try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
} */
}
}
public int getSum() {
return sum;
}
}
如果没有代码的注释部分,程序会出现数据损坏,每次运行时都不会为100。但我认为synchronized关键字应该获取sumAddOne方法的锁定,这是我程序的关键区域,允许每次一个线程访问此方法。
我也尝试使用ExecutorService,但它不会给所有运行提供100个。
public void task(){
ExecutorService s = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
s.execute(new Thread(new Runnable(){
@Override
public void run() {
sumAddOne();
}
}));
}
s.shutdown();
while(!s.isTerminated()){}
}
答案 0 :(得分:4)
在Task()中,你启动了100个线程(这很多),每个线程都要加1。
但是当Task完成时,你所知道的是100个线程正处于启动的某个过程中。在调用println()之前你不会阻塞,所以你怎么知道所有线程都已完成?
睡眠可能&#34;防止腐败&#34;只是因为它为系统提供了完成启动所有线程的时间。
除此之外,您正确使用同步。任何地方多个线程都可以写入你需要的同一个变量,而且一般来说(简化),如果你只是阅读,你就不需要它。
答案 1 :(得分:3)
正确使用Synchronized关键字,问题是您没有等待线程完成。这是一个可能的解决方案:
public class NonSynchro1 {
private static final ExecutorService executorService = Executors.newCachedThreadPool();
private int sum = 0;
public static void main(String[] args) {
NonSynchro1 n = new NonSynchro1();
n.task();
System.out.println(n.getSum());
executorService.shutdown();
}
public synchronized void sumAddOne() {
sum++;
}
public void task() {
List<Callable<Object>> callables = new ArrayList<>();
for (int i = 0; i < 100; i++) {
callables.add(() -> {
sumAddOne();
return null;
});
}
List<Future<Object>> futures;
try {
futures = executorService.invokeAll(callables);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
futures.forEach(future -> {
try {
future.get();
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
});
}
public int getSum() {
return sum;
}
}
首先,我们创建一个callables列表 - 一个将并行执行的函数列表。
然后我们在执行者服务上调用它们。 newCachedThreadPool
我在这里使用过,默认情况下有0个线程,它会创建尽可能多的执行所有传递的callables,线程将在空闲一分钟后被杀死。
最后,在for-each循环中,我们解决所有未来。 get()
调用将阻塞,直到执行程序服务执行该函数。如果它被抛入函数内部它也会抛出异常(没有调用get()
你根本就不会看到这样的异常)。
此外,当您想要正常终止程序时,最好关闭执行程序服务。在这种情况下,主方法结束时只有executorService.shutdown()
。如果不这样做,程序将在空闲线程被杀死一分钟后终止。但是,如果执行不同的执行程序服务,则空闲时可能不会终止线程,在这种情况下程序永远不会终止。
答案 2 :(得分:0)
为了完整起见:这是一个解决方案,展示了原始程序如何通过joining等待所有线程完成:
for (Thread t : n.task())
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
需要task
来返回它创建的线程。在这种情况下,我们不需要使用缓存管理器或集合来复杂化:简单的数组就可以。这是完整的课程:
public class TestSynchro1 {
private int sum = 0;
public synchronized void sumAddOne() {
sum++;
}
public Thread[] task(int n) {
Thread[] threads = new Thread[n];
for (int i = 0; i < n; i++) {
(threads[i] = new Thread(new Runnable() {
@Override
public void run() {
sumAddOne();
}
})).start();
}
return threads;
}
public static void main(String[] args) {
TestSynchro1 n = new TestSynchro1();
for (Thread t : n.task(100))
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(n.sum);
}
}