Java并发:与结果不一致

时间:2013-01-04 20:17:55

标签: java multithreading concurrency thread-safety

我创建了一个试图模拟多线程应用程序的测试包。假设有N个线程访问共享资源,在这种情况下是一个增量为整数并检查整数是奇数还是偶数的方法。我想要实现的是当方法结果等于50时,监视该值的线程应该能够停止所有线程并关闭进程。我希望这能给每个人一个清晰的画面。现在我遇到的问题是结果不时有所不同,它们是不一致的。下面是我写的代码。我已经使用了最多线程安全措施,所以我相信。

public class ThreadTestOne {

private static final java.util.concurrent.atomic.AtomicInteger number= new java.util.concurrent.atomic.AtomicInteger(0);
private static boolean stop=false; 
private static String orginaltime=gettime("hh:mm:ss");

static {
    try{

        java.util.concurrent.ExecutorService executor = java.util.concurrent.Executors.newFixedThreadPool(6);
        executor.execute(new MasterThread(executor));
        executor.execute(new Thread(new child1(),"Thread1"));
        executor.execute(new Thread(new child2(),"Thread2"));
        executor.execute(new Thread(new child3(),"Thread3"));
        executor.execute(new Thread(new child4(),"Thread4"));
        executor.execute(new Thread(new child5(),"Thread5"));

    }catch(Exception e){
        e.printStackTrace();
    }
}

private static final class child1 implements java.lang.Runnable{
    public void run(){
        while(stop!=true){
            try{
                getCount(this.getClass().getSimpleName());
                Thread.sleep(0000);
            }catch(java.lang.InterruptedException e){
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

private static final class child2 implements java.lang.Runnable{
    public void run(){
        while(stop!=true){
            try{
                getCount(this.getClass().getSimpleName());
                Thread.sleep(0000);
            }catch(java.lang.InterruptedException e){
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

private static final class child3 implements java.lang.Runnable{
    public void run(){
        while(stop!=true){
            try{
                getCount(this.getClass().getSimpleName());
                Thread.sleep(0000);
            }catch(java.lang.InterruptedException e){
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

private static final class child4 implements java.lang.Runnable{
    public void run(){
        while(stop!=true){
            try{
                getCount(this.getClass().getSimpleName());
                Thread.sleep(0000);
            }catch(java.lang.InterruptedException e){
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

private static final class child5 implements java.lang.Runnable{
    public void run(){
        while(stop!=true){
            try{
                getCount(this.getClass().getSimpleName());
                Thread.sleep(0000);
            }catch(java.lang.InterruptedException e){
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

private static final class MasterThread implements java.lang.Runnable{
    private java.util.concurrent.ExecutorService MasterExecutor=null;
    private MasterThread(java.util.concurrent.ExecutorService executor){
        this.MasterExecutor=executor;
    }
    public void run(){
         while(stop!=true){
             if(ThreadTestOne.getCurrNumber()==50){
                 stop=true;
                 MasterExecutor.shutdown();
                 System.out.println("Amount of time taken to execute is " +ThreadTestOne.elapsedTime(orginaltime)+ " seconds");
                 System.exit(0);
             }
         }
    }
}

private static synchronized void getCount(String ThreadName){

    System.out.println(ThreadName+" value is "+incrementgetNumber()+getKind());
}

private static final int incrementgetNumber(){

    return number.incrementAndGet();
}

private static final int getCurrNumber(){

    return number.get();
}

private static final String getKind(){

    return ((getCurrNumber()% 2) == 0) ? " and is an even number." : " and is an odd number.";
}

/*private static final void StartThreads(Thread ... threads){
    for (Thread thread : threads) {
        String ThreadName=thread.getName();
        long ThreadID=thread.getId();
        thread.start();
        System.out.println(ThreadName+" of ThreadID: "+ThreadID+" has been Started");
    }
}

private static final void StopThreads(Thread ... threads){
    for (Thread thread : threads) {
        if(thread!=null){
            String ThreadName=thread.getName();
            long ThreadID=thread.getId();
            System.out.println(ThreadName+" of ThreadID: "+ThreadID+" attempting to stop");
            thread.interrupt();
            System.out.println(ThreadName+" of ThreadID: "+ThreadID+" stopped");
        }
    }
}*/

private static long elapsedTime(String OriginalTime){
    java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("hh:mm:ss");
    long difference = 0;

    try {
         java.util.Date origTime = format.parse(OriginalTime);
         java.util.Date currTime = format.parse(gettime("hh:mm:ss"));
          difference = (currTime.getTime() - origTime.getTime())/1000; 
    } catch (Exception e) {
         e.printStackTrace();
    }
    return difference;
}

private static String gettime(String pattern){
    String timeString="";
    try{
     java.text.SimpleDateFormat format = new java.text.SimpleDateFormat(pattern);
     java.util.Date currentTime = new java.util.Date();
     timeString = format.format(currentTime);
    }
    catch(Exception e){
        e.printStackTrace();
    }
    return timeString;
}

public static void main (String []args){
    new ThreadTestOne();
}

}

我得到的结果如下

第一次试运行

    child5 value is 1 and is an odd number.
child1 value is 2 and is an even number.
child1 value is 3 and is an odd number.
child1 value is 4 and is an even number.
child5 value is 5 and is an odd number.
child5 value is 6 and is an even number.
child5 value is 7 and is an odd number.
child5 value is 8 and is an even number.
child5 value is 9 and is an odd number.
child5 value is 10 and is an even number.
child5 value is 11 and is an odd number.
child5 value is 12 and is an even number.
child5 value is 13 and is an odd number.
child5 value is 14 and is an even number.
child5 value is 15 and is an odd number.
child5 value is 16 and is an even number.
child5 value is 17 and is an odd number.
child5 value is 18 and is an even number.
child5 value is 19 and is an odd number.
child5 value is 20 and is an even number.
child5 value is 21 and is an odd number.
child5 value is 22 and is an even number.
child5 value is 23 and is an odd number.
child5 value is 24 and is an even number.
child5 value is 25 and is an odd number.
child5 value is 26 and is an even number.
child5 value is 27 and is an odd number.
child5 value is 28 and is an even number.
child5 value is 29 and is an odd number.
child5 value is 30 and is an even number.
child5 value is 31 and is an odd number.
child5 value is 32 and is an even number.
child5 value is 33 and is an odd number.
child5 value is 34 and is an even number.
child5 value is 35 and is an odd number.
child5 value is 36 and is an even number.
child5 value is 37 and is an odd number.
child5 value is 38 and is an even number.
child5 value is 39 and is an odd number.
child5 value is 40 and is an even number.
child5 value is 41 and is an odd number.
child5 value is 42 and is an even number.
child5 value is 43 and is an odd number.
child5 value is 44 and is an even number.
child5 value is 45 and is an odd number.
child5 value is 46 and is an even number.
child5 value is 47 and is an odd number.
child5 value is 48 and is an even number.
child5 value is 49 and is an odd number.
child5 value is 50 and is an even number.
child4 value is 51 and is an odd number.
child2 value is 52 and is an even number.
child3 value is 53 and is an odd number.
child1 value is 54 and is an even number.
Amount of time taken to execute is 0 seconds

第二次试运行

    child2 value is 112549 and is an odd number.
child2 value is 112550 and is an even number.
child2 value is 112551 and is an odd number.
child2 value is 112552 and is an even number.
child2 value is 112553 and is an odd number.
child2 value is 112554 and is an even number.
child2 value is 112555 and is an odd number.
child2 value is 112556 and is an even number.
child2 value is 112557 and is an odd number.
child2 value is 112558 and is an even number.
child2 value is 112559 and is an odd number.
child2 value is 112560 and is an even number.
child2 value is 112561 and is an odd number.
child2 value is 112562 and is an even number.
child2 value is 112563 and is an odd number.
child2 value is 112564 and is an even number.
child2 value is 112565 and is an odd number.
child2 value is 112566 and is an even number.
child2 value is 112567 and is an odd number.
child2 value is 112568 and is an even number.
child2 value is 112569 and is an odd number.
child2 value is 112570 and is an even number.
child2 value is 112571 and is an odd number.
child2 value is 112572 and is an even number.
child2 value is 112573 and is an odd number.
child2 value is 112574 and is an even number.
child2 value is 112575 and is an odd number.
child2 value is 112576 and is an even number.
child2 value is 112577 and is an odd number.
child2 value is 112578 and is an even number.
child2 value is 112579 and is an odd number.
child2 value is 112580 and is an even number.
child2 value is 112581 and is an odd number.
child2 value is 112582 and is an even number.
child2 value is 112583 and is an odd number.
child2 value is 112584 and is an even number.
child2 value is 112585 and is an odd number.
child2 value is 112586 and is an even number.
child2 value is 112587 and is an odd number.
child2 value is 112588 and is an even number.
child2 value is 112589 and is an odd number.
child2 value is 112590 and is an even number.
child2 value is 112591 and is an odd number.
child2 value is 112592 and is an even number.
child2 value is 112593 and is an odd number.
child2 value is 112594 and is an even number.
child2 value is 112595 and is an odd number.
child2 value is 112596 and is an even number.
child2 value is 112597 and is an odd number.
child2 value is 112598 and is an even number.
child2 value is 112599 and is an odd number.
child2 value is 112600 and is an even number.
child2 value is 112601 and is an odd number.
child2 value is 112602 and is an even number.
child2 value is 112603 and is an odd number.
child2 value is 112604 and is an even number.
child2 value is 112605 and is an odd number.
child2 value is 112606 and is an even number.
child2 value is 112607 and is an odd number.
child2 value is 112608 and is an even number.
child2 value is 112609 and is an odd number.
child2 value is 112610 and is an even number.
child2 value is 112611 and is an odd number.
child2 value is 112612 and is an even number.
child2 value is 112613 and is an odd number.
child2 value is 112614 and is an even number.
child2 value is 112615 and is an odd number.
child2 value is 112616 and is an even number.
child2 value is 112617 and is an odd number.
child2 value is 112618 and is an even number.
child2 value is 112619 and is an odd number.
child2 value is 112620 and is an even number.
child2 value is 112621 and is an odd number.
child2 value is 112622 and is an even number.
child2 value is 112623 and is an odd number.
child2 value is 112624 and is an even number.
child2 value is 112625 and is an odd number.
child2 value is 112626 and is an even number.
child2 value is 112627 and is an odd number.
child2 value is 112628 and is an even number.
child2 value is 112629 and is an odd number.
child2 value is 112630 and is an even number.
child2 value is 112631 and is an odd number.
child2 value is 112632 and is an even number.
child2 value is 112633 and is an odd number.
child2 value is 112634 and is an even number.
child2 value is 112635 and is an odd number.
child2 value is 112636 and is an even number.
child2 value is 112637 and is an odd number.
child2 value is 112638 and is an even number.
child2 value is 112639 and is an odd number.
child2 value is 112640 and is an even number.
child2 value is 112641 and is an odd number.
child2 value is 112642 and is an even number.
child2 value is 112643 and is an odd number.
child2 value is 112644 and is an even number.

第三次试运行

    child4 value is 1 and is an odd number.
child1 value is 2 and is an even number.
child3 value is 3 and is an odd number.
child3 value is 4 and is an even number.
child3 value is 5 and is an odd number.
child3 value is 6 and is an even number.
child3 value is 7 and is an odd number.
child3 value is 8 and is an even number.
child3 value is 9 and is an odd number.
child3 value is 10 and is an even number.
child3 value is 11 and is an odd number.
child3 value is 12 and is an even number.
child3 value is 13 and is an odd number.
child3 value is 14 and is an even number.
child3 value is 15 and is an odd number.
child3 value is 16 and is an even number.
child3 value is 17 and is an odd number.
child3 value is 18 and is an even number.
child3 value is 19 and is an odd number.
child3 value is 20 and is an even number.
child3 value is 21 and is an odd number.
child3 value is 22 and is an even number.
child3 value is 23 and is an odd number.
child3 value is 24 and is an even number.
child3 value is 25 and is an odd number.
child3 value is 26 and is an even number.
child3 value is 27 and is an odd number.
child3 value is 28 and is an even number.
child3 value is 29 and is an odd number.
child3 value is 30 and is an even number.
child3 value is 31 and is an odd number.
child3 value is 32 and is an even number.
child3 value is 33 and is an odd number.
child3 value is 34 and is an even number.
child3 value is 35 and is an odd number.
child3 value is 36 and is an even number.
child3 value is 37 and is an odd number.
child3 value is 38 and is an even number.
child3 value is 39 and is an odd number.
child3 value is 40 and is an even number.
child3 value is 41 and is an odd number.
child3 value is 42 and is an even number.
child3 value is 43 and is an odd number.
child3 value is 44 and is an even number.
child3 value is 45 and is an odd number.
child3 value is 46 and is an even number.
child3 value is 47 and is an odd number.
child3 value is 48 and is an even number.
child3 value is 49 and is an odd number.
child3 value is 50 and is an even number.
Amount of time taken to execute is 0 seconds
child2 value is 51 and is an odd number.

如果查看第1次和第3次测试运行,您将看到即使在达到50标记后线程仍继续执行。 第二次试运行令人费解。请建议问题是什么?

2 个答案:

答案 0 :(得分:2)

stop必须是易失性的,以便保证对它的修改在线程中可见。

请注意,由于主线程检查和停止操作不是原子操作,因此每次运行仍然不会有50个结果。此外,主线程完全有可能永远不会看到完全等于50的值,在这种情况下,它将永远运行。

答案 1 :(得分:0)

所以我确实接受了@jtahlborn和@ Clockwork-Muse的建议,并提出了以下建议。

public class ThreadTestOne {

private static final java.util.concurrent.atomic.AtomicInteger number= new java.util.concurrent.atomic.AtomicInteger(1);
private static final java.util.concurrent.atomic.AtomicBoolean stop= new java.util.concurrent.atomic.AtomicBoolean(false);
private static final int max=50;
private static final long sleepTime=0000;
private static String orginaltime=gettime("hh:mm:ss");

static {
    try{

        java.util.concurrent.ExecutorService executor = java.util.concurrent.Executors.newFixedThreadPool(6);
        executor.execute(new MasterThread(executor));
        executor.execute(new Thread(new child1("Thread1")));
        executor.execute(new Thread(new child2("Thread2")));
        executor.execute(new Thread(new child3("Thread3")));
        executor.execute(new Thread(new child4("Thread4")));
        executor.execute(new Thread(new child5("Thread5")));

    }catch(Exception e){
        e.printStackTrace();
    }
}

private static final class child1 implements java.lang.Runnable{
    private String threadName=""; 
    private child1(String threadName){
        this.threadName=threadName;
    }
    public void run(){
        Thread.currentThread().setName(threadName);
        while(true){
            try{
                getNumber(Thread.currentThread().getName());
                Thread.sleep(sleepTime);
            }catch(java.lang.InterruptedException e){
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

private static final class child2 implements java.lang.Runnable{
    private String threadName=""; 
    private child2(String threadName){
        this.threadName=threadName;
    }

    public void run(){
        Thread.currentThread().setName(threadName);
        while(true){
            try{
                getNumber(Thread.currentThread().getName());
                Thread.sleep(sleepTime);
            }catch(java.lang.InterruptedException e){
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

private static final class child3 implements java.lang.Runnable{
    private String threadName=""; 
    private child3(String threadName){
        this.threadName=threadName;
    }

    public void run(){
        Thread.currentThread().setName(threadName);
        while(true){
            try{
                getNumber(Thread.currentThread().getName());
                Thread.sleep(sleepTime);
            }catch(java.lang.InterruptedException e){
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

private static final class child4 implements java.lang.Runnable{
    private String threadName=""; 
    private child4(String threadName){
        this.threadName=threadName;
    }

    public void run(){
        Thread.currentThread().setName(threadName);
        while(true){
            try{
                getNumber(Thread.currentThread().getName());
                Thread.sleep(sleepTime);
            }catch(java.lang.InterruptedException e){
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

private static final class child5 implements java.lang.Runnable{
    private String threadName=""; 
    private child5(String threadName){
        this.threadName=threadName;
    }

    public void run(){
        Thread.currentThread().setName(threadName);
        while(true){
            try{
                getNumber(Thread.currentThread().getName());
                Thread.sleep(sleepTime);
            }catch(java.lang.InterruptedException e){
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

private static final class MasterThread implements java.lang.Runnable{
    private java.util.concurrent.ExecutorService MasterExecutor=null;
    private MasterThread(java.util.concurrent.ExecutorService executor){
        this.MasterExecutor=executor;
    }
    public void run(){
         while(true){
             if(stop.get()!=false){
                 MasterExecutor.shutdown();
                 System.out.println("Amount of time taken to execute is " +ThreadTestOne.elapsedTime(orginaltime)+ " seconds");
                 System.exit(0);
             }
         }
    }
}

public static synchronized void getNumber(String ThreadName){
    String result="";
    if(number.get()!=max){
        result=((number.get()%2)==0)?" and is an even number.":" and is an odd number.";
        System.out.println(ThreadName+" value is "+number.get()+result);
        number.incrementAndGet();
    }else{
        stop.set(true);
    }
}

private static long elapsedTime(String OriginalTime){
    java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("hh:mm:ss");
    long difference = 0;
    try {
         java.util.Date origTime = format.parse(OriginalTime);
         java.util.Date currTime = format.parse(gettime("hh:mm:ss"));
          difference = (currTime.getTime() - origTime.getTime())/1000; 
    } catch (Exception e) {
         e.printStackTrace();
    }
    return difference;
}

private static String gettime(String pattern){
    String timeString="";
    try{
     java.text.SimpleDateFormat format = new java.text.SimpleDateFormat(pattern);
     java.util.Date currentTime = new java.util.Date();
     timeString = format.format(currentTime);
    }
    catch(Exception e){
        e.printStackTrace();
    }
    return timeString;
}

public static void main (String []args){
    new ThreadTestOne();
}

}

现在解决方案现在已经保证了操作的一致性。谢谢大家,我希望这对学习java并发的其他人有好处。