java multi-threaded application development

In the previous blog java upgrade 2 related chapters , the basic knowledge about multithreading is introduced, you can read it, this chapter has an in-depth understanding of the application of multithreading.

1. Thread safety

For thread safety issues, first give an example:

//窗口售票问题
class MyThreadDemo implements Runnable {
    int ticket = 100;

    @Override
    public void run() {
        while (true){
            if (ticket>0) {
                try {
                    Thread.currentThread().sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"售票,票号为:"+ticket--);
            }else{
                break;
            }
        }
    }
}

public class ThreadTest {
    public static void main(String[] args){
        MyThreadDemo m = new MyThreadDemo();
        Thread t1 = new Thread(m);
        Thread t2 = new Thread(m);
        Thread t3 = new Thread(m);
        t1.start();
        t2.start();
        t3.start();
    }
}

Description of the problem:
The above multi-threaded ticketing has an error phenomenon.
Heavy ticket:
threadError01

Wrong vote:
threadError02

First, let's analyze why this problem occurs?
The ideal state we expect is:
threadDream

However, there is an extreme state:
threadWorry

This is because an exception thread participates in the process of operating the shared data, and the execution is not completed, resulting in a security problem in the shared data. The shared data in this instance is a ticket.

So, how to deal with the thread safety of the program?
After a thread has finished operating the shared data, other threads have the opportunity to participate in the operation of the shared data.

We also understand the principle, how does java achieve thread safety? There are two ways to implement
the synchronization mechanism using threads :

  • Synchronized code block

synchronized(同步监视器){//需要被同步的代码块(即操作共享数据的代码)}
1. Shared data: the same data (variable) that multiple threads operate together.
2. Synchronization monitor: Acted by an object of any class, whichever thread acquires the monitor will execute the synchronized code in curly brackets. Common name: lock.

Code:

class MyThreadDemo implements Runnable {
    int ticket = 100;
    Object object = new Object();

    @Override
    public void run() {
        //Object object = new Object();//不行,由成员变量变为局部变量,每创建一个线程,都会创建一个对象
        while (true){
            synchronized (object){//同步监视器(锁)可以由任何一个类的对象来充当,也可以使用this,表示当前对象,只new了一次。但是在继承的方式中,一定要注意使用this,可能创建了多个线程对象,要求是多个线程使用同一个锁,即使用同一个对象。
                if (ticket>0) {
                    try {
                        Thread.currentThread().sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"售票,票号为:"+ticket--);
                }else{
                    break;
                }
            }
        }
    }
}

threadTheory

  • Synchronized method

The synchronization method implementation has been given in the relevant chapters of java upgrade 2 , you can go to check it.

It declares the method of operating shared data synchronizedas a synchronous method, which ensures that when one thread executes this method, other threads wait outside until this thread finishes executing this method.

So is there a lock for the synchronization method? The answer is yes, and the lock is this. However, it should also be noted that in the way of using the thread created by inheritance, the synchronization method should also be used with caution, because its lock is this. It must be ensured that multiple threads share a lock.

  • Ways to use locks (understand)

2. The lazy thread safety problem of the singleton mode of the mutex

互斥锁Refers to a lock that can only be held by at most one thread at a time. Before jdk1.5, we usually used the synchronized mechanism to control access to shared resources by multiple threads. The keyword synchronizedis used to associate with the mutex of the object. When an object is synchronizeddecorated with, it indicates that the object can only be accessed by one thread at any time.
- Limitations of synchronization: The execution efficiency of the program is reduced
. - The lock of the synchronization method (non-static) is this.
- The lock for synchronized methods (static) is the current class itself.

Singleton mode lazy implementation:


class Singleton {

    private Singleton() {
    }

    private static Singleton instance = null;

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

public class TestSingleton {
    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        System.out.println(s1 == s2);
    }
}
output:
true

There will be thread safety issues. When multiple threads are executing at the same time, the first thread calls getInstance()into the if statement, but it has not been instantiated yet. If the thread hangs, the later threads will also enter and create another object, which may eventually return. Different Singleton objects.

To solve the problem of thread safety implementation:

public static Singleton getInstance() {
//如果第一个线程获取了单例的实例对象,后面的线程再获取实例的时候就不需要进入同步代码块了
    if (instance == null) {//多线程执行时,会先判断对象是否为null,如果为null,直接返回,无需等待进去同步代码块线程执行完毕,然后再去执行,提高了效率
        synchronized (Singleton.class) {//对于静态方法,使用但钱勒本身充当锁
            if (instance == null) {
                instance = new Singleton();
            }
        }
    }
    return instance;
}

To sum up, this method solves the thread safety problem of the lazy man and improves the efficiency, but in actual development, the hungry man is still used more, because this method is relatively complicated and not suitable for application.

3. Thread deadlock problem

死锁, means that different threads occupy the synchronization resources required by the other party respectively and do not give up, and then wait for the other party to give up the synchronization resources they need, forming a thread deadlock.

Example of deadlock:

public class TestDeadLock {

    static StringBuffer sb1 = new StringBuffer();
    static StringBuffer sb2 = new StringBuffer();

    public static void main(String[] args){

        new Thread(){
            public void run(){
                synchronized (sb1){
                    try {
                        Thread.currentThread().sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    sb1.append("A");
                    synchronized (sb2){
                        sb2.append("B");
                        System.out.println(sb1);
                        System.out.println(sb2);
                    }
                }
            }
        }.start();
        new Thread(){
            public void run(){
                synchronized (sb2){
                    sb1.append("C");
                    synchronized (sb1){
                        sb2.append("D");
                        System.out.println(sb1);
                        System.out.println(sb2);
                    }
                }
            }
        }.start();
    }

}

4. Thread communication

  1. three ways
    • wait(): Suspend the current thread and give up the CPU, synchronize resources, make other threads accessible and modify shared resources, while the current thread queues up for another access to the resource
    • notify(): wake up the thread with the highest priority in the thread that is queuing for synchronization resources and end the waiting
    • notifyAll(): Wake up all threads that are queuing for resources to end waiting.

Note: These three methods provided by Java.lang.Object can only be used in synchronized methods or synchronized code blocks, otherwise a java.lang.lllegalMonitorStateException will be reported.

Example:

/**
 * 线程通信
 * 使用两个线程打印1-100,线程1,线程2,交替打印
 */

class PrintNum implements Runnable {

    int num = 1;

    @Override
    public void run() {
        while (true) {
            synchronized (this){
                notify();
                if (num <= 100) {
                    try {
                        Thread.currentThread().sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + num);
                    num++;
                } else {
                    break;
                }


                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

public class TestCommunication {
    public static void main(String[] args) {
        PrintNum p = new PrintNum();
        Thread t1 = new Thread(p);
        Thread t2 = new Thread(p);
        t1.setName("甲");
        t2.setName("乙");
        t1.start();
        t2.start();
    }
}

output:
甲:1
乙:2
甲:3
乙:4
甲:5
乙:6
...
甲:97
乙:98
甲:99
乙:100

Regarding the relevant knowledge of multi-threading, I will come here for the time being. I will continue to update the content to be learned in the future. If you like it, please pay attention to Bai////呲 Ya.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325945041&siteId=291194637