作为我们大学课程的一部分,我们必须使用Java制作多线程下载服务器。 除了一点之外,一切都在顺利运行:我们必须让服务器在每次下载时显示每个项目的下载总数。到目前为止,我已经让它工作,除非两个客户同时请求它。代码如下,如果任何人有任何想法,我将非常感激。此外,我们必须包含thread.sleep部分,并且必须以复杂的方式递增计数器。
//Snipper from Protocol.java
if (theInput.equals("1")) {
theOutput = "The program displays a message... Another? Y or N";
DownloadCounter counter = new DownloadCounter();
count = DownloadCounter.getcount();//count is a var in Protocol.java it is static
int tmp = count;
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
System.out.println("sleep interrupted");
}
count = tmp + 1;
DownloadCounter.setcount(count);
System.out.println("Download Total " + count);
state = ANOTHER;
DownloadCounter:
//DownloadCounter.java
public class DownloadCounter {
private static int count;
public static synchronized int getcount(){
return count;
}
public static synchronized void setcount(int num){
DownloadCounter.count = num;
}
}
答案 0 :(得分:3)
根本问题是你有两个线程正在进行get,increment和set,所以请考虑这种情况:
Thread 1: set(5) // now count is 5
Thread 1: get() // Thread 1 gets 5
Thread 2: get() // Thread 2 gets 5
Thread 2: increments its local copy of count to 6
Thread 1: increments its local copy of count to 6
Thread 2: set(6) // now the count is 6
Thread 1: set(6) // the count is still 6, but it should be 7!!!
解决方案是实现一个递增方法,以线程安全的方式递增计数:
public synchronized void increment()
{
count++;
}
您还可以使用AtomicInteger
并避免锁定:
AtomicInteger count = new AtomicInteger(0);
public int getCount()
{
return count.get();
}
public void increment()
{
count.incrementAndGet();
}
您还声明计数器应计算每个项目的下载次数,但是,您当前的代码不会这样做。您当前的计数器将计算所有项目的所有下载。提示:如果你想为每个项目设置一个单独的计数器,那么你在DownloadCounter
中的所有内容都是静态的,并且这样做不会很好。
答案 1 :(得分:0)
DownloadCounter需要一种递增方法。仅使用getCount和setCount方法来增加计数器没有安全的方法。
Java有一个类AtomicInteger来处理这类事情。
此外,您只在DownloadCounter上调用静态方法,因此无需创建新实例。
答案 2 :(得分:0)
使其正确的关键是使get / increment / set成为原子操作。应该有一个同步的setCount
方法,而不是incrementCount()
方法。
您还可以使用AtomicInteger完全避免同步,并在incrementAndGet()
方法中使用其incrementCount()
方法。
请注意,指令DownloadCounter counter = new DownloadCounter();
完全没必要。该类应该有一个私有构造函数来防止这种不必要的实例化。