Java multithreading most complete summary 2-- how to thread synchronization

  Part of the basics of threads summarized herein, this the most important for multi-threaded programming, the most troublesome part of - synchronization to be a summary.

  Creating a thread is not difficult, the difficulty is how to make multiple threads can run good cooperation, most of the things that need multi-threaded processing is not fully independent, mostly related to the sharing of data herein, this is a summary of thread synchronization if local flawed, welcome to point out in the comments.

Why should sync

  Let's look at a simple example, there are two numbers num1, num2, now with 10 threads to do such a thing - every time a random number is subtracted from a num1, the added num2.

public class Demo1 {
    public static void main(String[] args) {
        Bank bank = new Bank();
        //创建10个线程,不停的将一个账号资金转移到另一个账号上
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                while (true) {
                    int account1 = ((Double) Math.floor(Math.random() * 10)).intValue();
                    int account2 = ((Double) Math.floor(Math.random() * 10)).intValue();
                    int num = ((Long) Math.round(Math.random() * 100)).intValue();
                    bank.transfer(account1, account2, num);
                    try {
                        Thread.sleep(((Double) (Math.random() * 10)).intValue());
                    } catch (Exception e) {
                    }
                }
            }).start();
        }
    }
}

class Bank {
    /**
     * 10个资金账户
     */
    public int[] accounts = new int[10];

    public Bank() {
        Arrays.fill(accounts, 1000);
    }

    public void transfer(int from, int to, int num) {
        accounts[from] -= num;
        accounts[to] += num;
        //计算和
        int sum = 0;
        for (int j = 0; j < 10; j++) {
            sum += accounts[j];
        }
        System.out.println(sum);
    }
}
复制代码

Under normal circumstances, no matter what time of the capital account and 10000. However, should all really so? Run the program and not equal to 10000 will find that after a period of time, can become large or may become smaller.

competition

  The above code in more than one program at the same time to update your account information, so there was competition. Suppose two threads simultaneously executed following a code for:

accounts[account1] -= num;
复制代码

The code is not atomic, it may be processed into the following three instructions:

  1. The accounts [account1] is loaded into the register
  2. Reduce the value of num
  3. The result is written back to accounts [account1]

The problem described here only in the case of single-core (as there will be multi-core problem), not a single core running two threads simultaneously, if a thread A executes the third step, deprived of the right to run the thread begins execution completed B the entire process, and then continue running thread a third step, which resulted in an error, the result of covering the results of the thread a thread B, the total amount is no longer correct. As shown below:

competition

How to synchronize

Lock objects

  In order to prevent concurrent data lead to confusion, Java language provides synchronized keyword, and joined the class when ReentrantLock of Java SE 5. synchronized keyword automatically provides a lock and related conditions, the back say. ReentrantLock using substantially the following:

myLock.lock()//myLock是一个ReetrantLock对象示例
try{
    //要保护的代码块
}finally{
    //一定要在finally中释放锁
    myLock.unlock();
}
复制代码

  Any of the above structure ensures that only one thread enters a critical section, once a thread calls the lock method to get the lock, all other threads will be blocked in the lock method, the calling thread until the lock unlock methods.

  The transfer method ban class lock code is as follows:

class Bank {
    /**
     * 10个资金账户
     */
    public int[] accounts = new int[10];

    private ReentrantLock lock = new ReentrantLock();

    public Bank() {
        Arrays.fill(accounts, 1000);
    }

    public void transfer(int from, int to, int num) {
        try {
            lock.lock();
            accounts[from] -= num;
            accounts[to] += num;
            //计算和
            int sum = 0;
            for (int j = 0; j < 10; j++) {
                sum += accounts[j];
            }
            System.out.println(sum);
        } finally {
            lock.unlock();
        }
    }
}
复制代码

After locking, no matter how many threads to run simultaneously, the data will not lead to confusion.

  Lock is reentrant and thread holding the lock may have been repeated acquire a lock already held. There is a lock hold count (hold count) to keep track of nested calls lock method. Each time lock count + 1, unlock time counted -1, 0, when the lock latch is released.

  Can with a lock fairness policy by boolean parameter tectonic belt - new ReentrantLock(true). Fair locks preference longest-waiting thread. But will result in significantly lower performance, but even with fair locks, there is no guarantee thread scheduler is fair.

Conditions Object

  Usually we encounter such a problem, when one thread acquires the lock, find the need to meet certain conditions in order to continue to the next execution, which requires a condition object to manage the lock has been acquired but do not do useful work thread.

  Now consider a plus to transfer restrictions, only sufficient funds account to the account as the roll-out, but also that they can not be negative. Note The following code is not feasible:

if(bank.accounts[from]>=num){
    bank.transfer(from,to,num);
}
复制代码

Because Multithreading is likely if the judge is successful, the data is just another thread changed.

  You may be achieved by determining target conditions:

class Bank {
    /**
     * 10个资金账户
     */
    public int[] accounts = new int[10];

    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public Bank() {
        Arrays.fill(accounts, 1000);
    }

    public void transfer(int from, int to, int num) {
        try {
            lock.lock();
            while (accounts[from] < num) {
                //进入阻塞状态
                condition.await();
            }
            accounts[from] -= num;
            accounts[to] += num;
            //计算和
            int sum = 0;
            for (int j = 0; j < 10; j++) {
                sum += accounts[j];
            }
            System.out.println(sum);
            //通知解除阻塞
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
复制代码

  In the while loop is judged whether, if the condition is not satisfied, call the awaitmethod into the blocked state, while giving up the lock. This allows other threads a chance to give an account to transfer funds also turn out to satisfy the judgment condition.

  When a thread finishes a job transfer, you should call signalAllthe method so that all the contact block threads blocked, because the judge could meet the conditions, you can continue the transfer operation.

  Note: Calls signalAllwill not immediately activate a waiting thread, just contact with blocking state, so that they can acquire the lock thread through competition, while judge continued.

  There is also a method signalof random unblock a thread. Here it could lead to deadlock.

synchronized keyword

  On one of the Lock and Condition provides a powerful synchronization control for developers. But most cases do not need such a complicated control. Starting java 1.0 version, Java each object has an internal lock. If a method synchronizeddeclaration, then the object's lock will protect the entire process is automatic acquisition method call inside the lock, internal lock automatically released at the end of the method.

  ReentrantLock lock with the same, there are internal lock wait / notifyAll / notify methods, correspondence is as follows:

  • wait corresponding to await
  • notifyAll corresponds signalAll
  • notify the corresponding signal is distinctive method name is because wait these methods are final method of the Object class, in order to not conflict, ReentrantLockthe class method needs to be renamed.

  synchronized with the ban to achieve the following classes:

class Bank {
    /**
     * 10个资金账户
     */
    public int[] accounts = new int[10];

    private ReentrantLock lock = new ReentrantLock();
//    private Condition condition = lock.newCondition();

    public Bank() {
        Arrays.fill(accounts, 1000);
    }

    synchronized public void transfer(int from, int to, int num) {
        try {
//            lock.lock();
            while (accounts[from] < num) {
                //进入阻塞状态
//                condition.await();
                this.wait();
            }
            accounts[from] -= num;
            accounts[to] += num;
            //计算和
            int sum = 0;
            for (int j = 0; j < 10; j++) {
                sum += accounts[j];
            }
            System.out.println(sum);
            //通知解除阻塞
//            condition.signalAll();
            this.notifyAll();
        } catch (Exception e) {
            e.printStackTrace();
        }
//        finally {
//            lock.unlock();
//        }
    }
}
复制代码

  Static methods can be declared as synchronized, call this method, access to the internal lock class object corresponding to the class.

How to use the code

  • The best neither Lock / Condition not use the synchronized keyword, mostly java.util.concurrent package can be used in class to complete data synchronization case, the package type are thread safe. It will be mentioned next one.

  • If you can use synchronized, try to use it, both to reduce the amount of code, reducing the chance of error.

  • If the above does not resolve the problem, it will only use the Lock / Condition a.

Benpian all the code used: GitHub

Original article published on: www.tapme.top/blog/detail...

Scan code concerned about micro-channel public number: FleyX study notes, for more dry goods

Guess you like

Origin juejin.im/post/5d1ab3986fb9a07ee63f7e4f