java-knowledge of thread synchronization

1. Concurrency

The same object is operated by multiple threads at the same time-buying tickets, buying meals, withdrawing money...

In real life, queuing to solve

Use the queue to solve the program.

2. Queue and lock

Multiple threads in the same process share a storage space, which will cause an access conflict! ! , The introduction of the lock mechanism synchronized , when a thread obtains the exclusive lock of the object and monopolizes the resource, other threads must wait and release the lock after use.

There is a problem

  • Performance issues
  • If a high-priority thread waits for a low-priority thread, the priority is inverted, causing performance problems.

3. Examples

Unsafe ticket purchase-there is a conflict
/**
 * 不安全
 */

//多个线程同时操作一个对象
//买火车票——对象车票
//存在线程并发的bug
public class Demo3 implements Runnable{
    
    

    //票数
    int numberTickets = 10;

    //线程执行代码
    public void run() {
    
    
        while (numberTickets>0){
    
    
            //模拟延时
            try {
    
    
                Thread.sleep(200);
            }catch (InterruptedException e){
    
    
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"拿到了票"+numberTickets--);

        }
    }

    public static void main(String[] args) {
    
    
        Demo3 demo3 = new Demo3();
        //三个人同时抢票
        new Thread(demo3,"小明").start();
        new Thread(demo3,"小惠").start();
        new Thread(demo3,"黄牛党").start();
    }
}

There is a conflict

Insert picture description here

Unsafe withdrawal

Code

public class BankN {
    
    

    public static void main(String[] args) {
    
    
        Account account = new Account(1000000,"小傅的账户");
        Drawing you = new Drawing(account,10000,"XiaoFu");
        Drawing girlFriend = new Drawing(account,100000,"girlFriend");

        you.start();
        girlFriend.start();

    }
}

class Account{
    
    
    int money;//余额
    String cardName;//卡名

    public Account(int money, String cardName) {
    
    
        this.money = money;
        this.cardName = cardName;
    }
}

class Drawing extends Thread{
    
    
    Account account;//账户

    int drawing_money;//取了多少钱

    int nowMoney;//手里有多少钱

    public Drawing(Account account,int drawing_money,String T_name){
    
    
        super(T_name);
        this.account = account;
        this.drawing_money = drawing_money;
    }

    @Override
    public void run() {
    
    
        if (account.money<drawing_money){
    
    
            System.out.println(Thread.currentThread().getName()+"钱不够取不了");
            return;
        }

        //模拟网络延时
        try {
    
    
            Thread.sleep(1000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

        account.money = account.money-drawing_money;//账户减少钱
        nowMoney = nowMoney+drawing_money;//手里的钱增加

        System.out.println(account.cardName+"余额为:"+account.money);
        //Thread.currentThread().getName() = this.getName()
        System.out.println(this.getName()+"手里的钱:"+nowMoney);

    }
}

result
Insert picture description here

Why is there a conflict

Take the last ticket as an example. Each process has its own memory, so everyone thinks that there is a ticket. When the ticket is bought, it is found that the ticket is 0;

That is, two threads operate on the same data at the same time. The result is not 10000

/**
 * 线程是不安全的
 */
public class ThreadUn {
    
    

    public static void main(String[] args) throws InterruptedException {
    
    

        List<Thread> list = new ArrayList<>();

        for (int i = 0; i < 10000; i++) {
    
    
            new Thread(()->{
    
    
                list.add(Thread.currentThread());
            }).start();
        }

        Thread.sleep(3000);

        System.out.println(list.size());

    }
}

4. Implementation mechanism

After improvement-resolve conflicts through locks (synchronized keyword)
  • synchronized方法
  • synchronized块

Every object has a lock

Defect: Declaring a large method as synchronized is inefficient.

The content that needs to be modified in the method needs to be locked.

Insert picture description here

1)synchronized方法
//synchronized 同步方法——锁的是this
private synchronized void buy() throws InterruptedException {
    
    
    if (numberTickets<=0){
    
    
        flag = false;
        return;
    }
    //模拟网络延时
    Thread.sleep(200);
    //模拟买票
    System.out.println(Thread.currentThread().getName()+"拿到了票"+numberTickets--);
}
2) synchronized块

The object of the lock should be the object of addition, deletion, modification and inspection-the amount of change

The default lock is this-so you need to lock the account instead of the run method.

// synchronized默认锁的是this
public void run() {
    
    

    // synchronized块
    synchronized (account){
    
    
        if (account.money<drawing_money){
    
    
            System.out.println(Thread.currentThread().getName()+"钱不够取不了");
            return;
        }

        //模拟网络延时
        try {
    
    
            Thread.sleep(1000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

        account.money = account.money-drawing_money;//账户减少钱
        nowMoney = nowMoney+drawing_money;//手里的钱增加

        System.out.println(account.cardName+"余额为:"+account.money);
        //Thread.currentThread().getName() = this.getName()
        System.out.println(this.getName()+"手里的钱:"+nowMoney);
    }

}

Add a synchronized block in the run method body

public static void main(String[] args) throws InterruptedException {
    
    

    List<Thread> list = new ArrayList<>();

    for (int i = 0; i < 10000; i++) {
    
    
        new Thread(()->{
    
    
            synchronized (list){
    
    
                list.add(Thread.currentThread());
            }
        }).start();


    }

    Thread.sleep(1000);

    System.out.println(list.size());

}
3) java concurrent package-concurrent linked list
public class CopyOnWriteArrayList<E>
extends Object
implements List<E>, RandomAccess, Cloneable, Serializable

A thread-safe variable in all the changes ArrayList( , add, setetc.) are implemented by a new version of the underlying array.

This is usually expensive, but may be more efficient than choosing when the traversal operation greatly exceeds the mutation. It is useful when you cannot or do not want to synchronize the traversal, but you need to eliminate interference between concurrent threads. The "snapshot" style iterator method uses a reference to the state of the array when creating the iterator. The lifetime of the iterator has never changed in this array, so interference is impossible, and the iterator is guaranteed not to be lost ConcurrentModificationException. Iterators will not reflect additions, deletions, or changes to the list since the iterator was created. Yuan change the operation of the iterator itself ( remove, , setand add) do not support. These methods put UnsupportedOperationException.

All elements are allowed, including null.

Memory consistency effect: with other concurrent collections, the behavior of the thread CopyOnWriteArrayList before placing the object in a happen-before action CopyOnWriteArrayListto access and remove elements from another thread .

//java实现的线程安全的链表
public class TestJUC {
    
    
    public static void main(String[] args) {
    
    
        CopyOnWriteArrayList<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 1000; i++) {
    
    
            new Thread(()->{
    
    
                copyOnWriteArrayList.add(Thread.currentThread().getName());
            }).start();
        }


        try {
    
    
            Thread.sleep(10000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println(copyOnWriteArrayList.size());
    }
}

5. Deadlock problem

A group of threads hold each other's required resources (locks), and none of them can be released.

synchronized (Object){
    
    
//代码体
}

synchronized (Object) is equivalent to locking the Object.

After the code body is executed, it is equivalent to releasing the lock.

example

public class TestDeadLock {
    
    

    public static void main(String[] args) {
    
    
        Makeup g1 = new Makeup(0,"灰姑娘");
        Makeup g2 = new Makeup(1,"白雪公主");

        g1.start();
        g2.start();
    }

}

//口红
class Lipstick{
    
    

}

//镜子
class Mirror{
    
    

}

class Makeup extends Thread{
    
    
    //需要的资源,用static表示只有一份资源
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();

    int choice;
    String girlName;

    public Makeup(int choice,String girlName){
    
    
        this.choice = choice;
        this.girlName = girlName;
    }

    //线程运行主体
    public void run() {
    
    
        //化妆
        make_up();
    }

    //互相持有对方的资源
    private void make_up(){
    
    
        if (choice==0){
    
    
            //获得口红的锁
            synchronized (lipstick){
    
    
                System.out.println(this.girlName+"获得口红的锁");
                try {
    
    
                    Thread.sleep(300);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                //欲获得镜子
                synchronized (mirror){
    
    
                    System.out.println(this.girlName+"获得镜子的锁");
                }
            }
        }
        if (choice==1){
    
    
            //获得口红的锁
            synchronized (mirror){
    
    
                System.out.println(this.girlName+"获得镜子的锁");
                try {
    
    
                    Thread.sleep(500);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                //欲获得镜子
                synchronized (lipstick){
    
    
                    System.out.println(this.girlName+"获得口红的锁");
                }
            }
        }
    }
}

Solve the problem-release after getting the lock:

//互相持有对方的资源
private void make_up(){
    
    
    if (choice==0){
    
    
        //获得口红的锁
        synchronized (lipstick){
    
    
            System.out.println(this.girlName+"获得口红的锁");
            try {
    
    
                Thread.sleep(300);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        //欲获得镜子
        synchronized (mirror){
    
    
            System.out.println(this.girlName+"获得镜子的锁");
        }
    }
    if (choice==1){
    
    
        //获得镜子的锁
        synchronized (mirror){
    
    
            System.out.println(this.girlName+"获得镜子的锁");
            try {
    
    
                Thread.sleep(500);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        //欲获得口红
        synchronized (lipstick){
    
    
            System.out.println(this.girlName+"获得口红的锁");
        }
    }
}

Summary: the necessary conditions for deadlock

Insert picture description here

Guess you like

Origin blog.csdn.net/joey_ro/article/details/109963389