Locks and synchronized

Lock the common concept

  • Mutually exclusive: that only one thread of execution
  • Critical section: a mutex section of code that needs to be executed
  • Fine-grained lock: a protected resource meticulous management with different locks. Fine-grained locking can increase the degree of parallelism, performance optimization is an important means of
  • Deadlock: a group of threads compete for resources with each other waiting for each other, leading to "permanent" blocking phenomenon.

Best practices with locks

  1. When the lock is always only then update the member variables of the object.
  2. Always lock only when accessing the variable member variables.
  3. Never call another object's methods when locked.
  4. The resulting reduced hold time, reducing lock granularity.

Synchronous and asynchronous

  • If you need to call the method wait for the results is synchronized; if you do not wait for the results is asynchronous.
  • Java code synchronization is the default approach.

How to implement a program to support asynchronous:

  1. Asynchronous call: the caller to create a child thread, then the child thread execution method call.
  2. Asynchronous Methods: the callee; when implemented method, appears to create a thread to perform the main logic, the main thread direct return.

synchronized

class  X{
    //修饰非静态方法
    synchronized void foo(){
       //临界区
    }
    //修饰静态方法
    synchronized static void bar(){
       //临界区
    }
    
    //修饰代码块
    Object obj = new Object();
    void baz(){
        synchronized(obj){
            //临界区
        }
    }
}

Java compiler will automatically add locking lock () and unlock unlock () before and after the synchronized method or block of code modification, the benefits of doing so is locking lock () and unlock unlock () must occur in pairs, after all Remember to unlock the unlock (), but a deadly Bug (meaning other threads can only wait the dead).

Modified static method:
//修饰静态方法是用当前类的字节码文件作为锁
class  X{
    //修饰静态方法
    synchronized(X.class) static void bar(){
       //临界区
    }
}
Non-static method modified:
//修饰非静态方法是用当前对象作为锁
class  X{
    //修饰非静态方法
    synchronized(this) static void bar(){
       //临界区
    }
}

How a lock to protect multiple resources

Subject to reasonable relationship between the protection of resources and the lock should be N: 1 relationship, which means you can use a lock to secure more resources, but can not use more than the locks to protect a resource,

Use the correct posture lock

As an example in accordance with the transfer business

Example 1:

public class Account {
    /**
     *锁:保护账⼾余额
     */
    private final   Object  balLock = new Object();
    /**
     * 账⼾余额
     */
    private Integer balance;
   
    /**
     * 错误的做法
     * 非静态方法的锁是this, 
     * this这把锁可以保护自己的余额this.balance,保护不了别人的余额 target.balance
     * 
     */
   synchronized void transfer(Account target,int amt){
        if (this.balance > amt) {
            this.balance -= amt;
            target.balance += amt;//这段代码会出现线程安全,要保证线程安全的话要使用同一个锁
        }
    }
}

Example Two:

public class Account {
    /**
     *锁:保护账⼾余额
     */
    private final   Object  balLock = new Object();
    /**
     * 账⼾余额
     */
    private Integer balance;
   

    /**
     * 正确的做法,但是会导致整个转账系统的串行
     *
     * Account.class是所有Account对象共享的,
     * 而且这个对象是Java虚拟机在加载Account类的时候创建的,
     * 所以我们不用担心它的唯一性
     *
     * 这样还有个弊端:所有的转账都是串行了
     */
    void transfer2(Account target,int amt){
        synchronized(Account.class){
            if (this.balance > amt) {
                this.balance -= amt;
                target.balance += amt;
            }
        }
    }
}

In this case the transfer operation has become a serial, normal logic should only lock into account and was transferred to the account; transfers without affecting other operations. Minor renovation:

Example Three:

public class Account {
    /**
     *锁:保护账⼾余额
     */
    private final Object lock;
    /**
     * 账⼾余额
     */
    private Integer balance;
   
    //私有化无参构造
    private Account(){}
    //设置一个传递lock的有参构造
    private Account(Object lock){
        this.lock = lock;
    }
    
    /**
     * 转账
     */
    void transfer(Account target,int amt){
        //此处检查所有对象共享锁
        synchronized(lock){
            if (this.balance > amt) {
                this.balance -= amt;
                target.balance += amt;
            }
        }
    }
}

Although able to solve the problem, but it requires to create the Account object when this method must pass the same object,

There is too much trouble passing objects, writing tedious lack of feasibility.

Example Four:

public class Account {
    
    /**
     * 账⼾余额
     */
    private Integer balance;
    
    /**
     * 转账
     */
    void transfer(Account target,int amt){
        //此处检查所有对象共享锁
        synchronized(Account.class){
            if (this.balance > amt) {
                this.balance -= amt;
                target.balance += amt;
            }
        }
    }
}

With Account.class as a shared lock, the lock range is too large. Account.class is shared by all the Account object, and this object is a Java virtual machine created when loading the Account class, so we do not worry about its uniqueness. Account.class use as a shared lock, we do not need to pass the Account when you create an object.

So that new problems arise as though with Account.class mutex to solve the problem of the transfer of business inside the bank, although the concurrent program is not a problem, but the transfer operation of all accounts are serial, such as account transfer A account B, C account transfer account transfer operation D both the real world is parallel, but in this program where he was serialized, this is the case, poor performance. So if this method is complicated by the amount of consideration is not OK

The correct wording is such that (the use of fine-grained locking):

Example five:

public class Account {
    
    /**
     * 账⼾余额
     */
    private Integer balance;
    
    /**
     * 转账
     */
    void transfer(Account target,int amt){
        //锁定转出账户
        synchronized(this){
             //锁住转入账户
            synchronized(target){
                if (this.balance > amt) {
                    this.balance -= amt;
                    target.balance += amt;
                }
            }
        }
    }
}

Let us think in ancient times, there is no information that there really is a form of account books, and each has an account books, these books are stored in a unified file rack. Bank teller gave us when transfers going to turn out file shelves and books were getting books into the hands, and then do the transfer. The teller may encounter the following three cases she took the books:

  1. File shelves and books out exactly turn into books, then while away;
  2. If the file rack only turn into one of the books and the books, and that the teller would put some file shelves books get our hands on, while waiting for the other teller sent back to the other books;
  3. Out of books and into the books are not, then this teller waiting for two books are sent back.

Fine-grained locks may deadlock

  • Deadlock: a group of threads compete for resources with each other waiting for each other, leading to "permanent" blocking phenomenon.
  • Two threads holding each other's resources are not released from each other will lead to a deadlock,
  • Use fine-grained locking can lead to deadlock

If there is to be a transfer seating customers find teller services: transfer account account A B 100 yuan, when the other customers find John Doe may also be a teller transfer services: transfer account Account B A 100 Yuan, thus simultaneously Zhang and Li go get the file shelves books, this time there could accidentally Joe Smith got the books a, John Doe got the books B. Joe Smith got more books after books A B (B books John Doe has been taken away), while John Doe waiting to get the books after books B A (A books Joe Smith has been taken away), they have to wait how long? They'll wait forever ... because Joe Smith does not send back the books A, B John Doe nor will send the books back. We tentatively called dead wait.

How to avoid deadlocks
  1. Mutually exclusive, shared resources X and Y can only be occupied by a thread;
  2. Possession and wait, the thread T1 has been made to share resources X, Y while waiting for a shared resource, and does not release a shared resource x;
  3. Can not seize, other threads can not be forced to seize the resource thread T1 possession;
  4. Circular wait, wait thread 1 thread T2 possession of resources, waiting for a resource thread thread T2 T1 possession, circulation is waiting.

As long as one can avoid damage deadlock

Wait - notification mechanism

Implement wait with synchronized - notification mechanism

  • synchronized with the wait (), notif (), notifyAll () these three methods can be easily achieved.
  • wait (): the current thread releases the lock, enter the blocked state
  • notif (), notifAll (): notification thread has blocked can continue to perform, the thread into an executable state
  • notif () will randomly notify a thread waiting for bad teams
  • notifyAll () notifies all threads waiting in the queue, it is recommended to use notifAll ()

wait and sleep differences:

sleep is the method of Object, wait method of Thread

wait will release the lock, sleep will not release the lock

wait need notif wake, sleep time setting, time to wake up

no need to wait to catch the exception, and sleep needs

wait (): the current thread into the blocked


**** If the code word is not easy to have to help you Give me a concern ****

**** love life love technology QQ group: 894 109 590 ****

Guess you like

Origin www.cnblogs.com/freeoldman/p/11514759.html