Multithreading sum, credited the wrong use of a synchronized

  

  to sum up:

  1. If the single-threaded environment, data dependency exists some method for operating a shared variable, the multi-threaded environment is a group of atoms that they must operate, and is exclusive of any modifications shared variables. Method whether the read program exclusive need to see the design, such as the CopyOnWrite mode, these operations do not mutually exclusive and atomic read operation of shared variables, the reading efficiency can be improved, but the disadvantage is not guaranteed every time a read operation are read is the latest value.

  2. To ensure the correctness of multi-threaded task, it is based on the correctness of each thread to access shared variables to be guaranteed.

  3. We also must ensure that data dependency or control methods rely on the presence of multi-threaded environment, the operating results of the visibility of the other threads and orderly operation of the other threads for the. happen-before principle is based on these two points.

  4. particular attention to the absence of data-dependent single-threaded case, but other threads to execute related movements. Since there is no data dependency single thread, the compiler is likely to be out of order execution. Such as modifying the shared variable and wake up other threads, threaded under the two movements is not dependent on the presence of data, how order execution will not affect the results in the single-threaded. However, multi-threaded environment, thread to be awakened may be required to work in accordance with the value of the shared variable, these two actions is dependent on the existence of actual data in a multithreaded environment.

  The questions were very simple to use multi-threading and seeking one hundred million number. This article is to summarize the idea of ​​multi-threaded programming, ensure the accuracy of multi-threaded task, each thread-based security access to shared variables to be guaranteed.

  Define the shared data:

public class ArraySource {

    // source array 
    Private  int [] Source;
     // accumulation result 
    Private  int Result = 0 ;
     // number of threads currently operating 
    Private  int threadNum;

    ArraySource(int[] source, int threadNum) {
        this.source = source;
        this.threadNum = threadNum;
    }

    public int[] getSource() {
        return this.source;
    }

    public int getResult() {
        return this.result;
    }

    public void setResult(int result) {
        this.result = result;
    }

    public int getThreadNum() {
        return this.threadNum;
    }

    public void setThreadNum(int threadNum) {
        this.threadNum = threadNum;
    }

}

  Define threaded tasks:

public class SumThread extends Thread {
    private int begin;
    private int end;
    ArraySource source;
    Object lock = new Object();

    SumThread(int begin, int end, ArraySource source) {
        this.begin = begin;
        this.end = end;
        this.source = source;
    }

    @Override
    public void run() {
        if (this.source == null || this.begin >= this.end) {
            throw new NullPointerException("非法入参!");
        }
        int re = 0;
        int[] sourceArray = this.source.getSource();
        for (int i = begin; i <= end; i++) {
            re += sourceArray[i];
        }
        synchronized (lock) {
            source.setResult(source.getResult() + re);
            source.setThreadNum(source.getThreadNum() - 1);
        }
    }
}

  The main function:

public class Test {

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 1000; i++) {
            int re = test();
            if (re != 100000000) {
                System.out.println ( "first" + i + "error occurred, the result is" + Re);
                 BREAK ;
            }
        }
        System.out.println ( "Test End" );
    }

    public static int test() throws InterruptedException {
        int[] source = new int[100000000];
        for (int i = 0; i < 100000000; i++) {
            source[i] = 1;
        }
        long beginTime = System.currentTimeMillis();
        int re = 0;
        for (int i = 0; i < 100000000; i++) {
            re += source[i];
        }
        System.out.println ( "single thread is used:" + (System.currentTimeMillis () - beginTime));
        System.out.println ( "single-threaded results:" + Re);

        ArraySource arraySource = new ArraySource(source, 4);
        SumThread thread0 = new SumThread(0, 20000000, arraySource);
        SumThread thread1 = new SumThread(20000001, 40000000, arraySource);
        SumThread thread2 = new SumThread(40000001, 60000000, arraySource);
        SumThread thread3 = new SumThread(60000001, 99999999, arraySource);
//        SumThread thread4 = new SumThread(80000001, 99999999, arraySource);
        beginTime = System.currentTimeMillis();
        thread0.start();
        thread1.start();
        thread2.start();
        thread3.start();
//         thread4.start (); 
        the while (arraySource.getThreadNum () = 0! ) {
 //             the Thread.sleep (500);
 //             System.out.println ( "there are:" + arraySource.getThreadNum () + " in the working threads; and current is: "+ arraySource.getResult ()); 
        }
        System.out.println ( "multi-threaded use is:" + (System.currentTimeMillis () - beginTime));
        System.out.println ( "multi-threaded results:" + arraySource.getResult ());
         return arraySource.getResult ();
    }
}

  The main function is executed a thousand times the code to verify the correctness of the program, the program ultimately proved to be reliable.

  Remember a wrong wording:

public class ArraySource {

    // source array 
    Private  int [] Source;
     // accumulation result 
    Private  int Result = 0 ;
     // number of threads currently operating 
    Private  int threadNum;

    ArraySource(int[] source, int threadNum) {
        this.source = source;
        this.threadNum = threadNum;
    }

    public int[] getSource() {
        return this.source;
    }
public  int getResult() {
synchronized(this) {
return this.result;
}
}

public void setResult(int result) {
synchronized(this) {
this.result = result;
}
}

public int getThreadNum() {
synchronized(this) {
return this.threadNum;
}
}

public void setThreadNum(int threadNum) {
synchronized(this) {
this.threadNum = threadNum;
}
}
 

  This is equivalent to writing:

    @Override
    public void run() {
        if (this.source == null || this.begin >= this.end) {
            throw new NullPointerException("非法入参!");
        }
        int re = 0;
        int[] sourceArray = this.source.getSource();
        for (int i = begin; i <= end; i++) {
            re += sourceArray[i];
        }
        int totalRe=source.getResult();
        source.setResult (totalRe + re);
        int sharedThreadNum=source.getThreadNum();
        source.setThreadNum( sharedThreadNum - 1);
    }

  First obtain a lock read operation, after releasing the write operation to acquire a lock, and there is no guarantee atomic operations.

Guess you like

Origin www.cnblogs.com/niuyourou/p/12417138.html