java basics---multithreading

java basics - multithreading


1. The concept of multithreading

  • Concepts of processes, threads, and multithreading:

    • Process: A program in progress.
    • Thread: A unit of control (execution path) in a process that is responsible for program execution.
  • The benefits of multithreading: Solve the problem of multiple parts of code running at the same time.

  • Disadvantages of multithreading: Too many threads will lead to a decrease in efficiency.

2. Method 1 to create a thread: Inherit the Thread class

  1. Define a class that inherits the Thread class.

  2. Override the run method in the Thread class.

  3. Directly create a subclass object of Thread to create a thread.

  4. Call the start method to start the thread and call the thread's run method to execute.

3. Create thread method 2: Implement the Runnable interface

  1. Define a class that implements the Runnable interface.

  2. Override the run method in the interface and encapsulate the thread's task code into the run method.

  3. Create a thread object through the Thread class, and pass the subclass object of the Runnable interface as the parameter of the constructor of the Thread class.

  4. Call the start method of the thread object to start the thread.

  5. The benefits of implementing the Runnable interface:

    • The task of the thread is separated from the subclass of the thread and encapsulated separately, and the task is encapsulated into an object according to the object-oriented idea.
    • Avoid the limitations of java single inheritance. Therefore, the second way of creating threads is more commonly used.

4. Thread security issues

  • Causes of thread safety issues:

    1. Multiple threads are manipulating shared data.
    2. There are multiple threads of code that operate on shared data.
  • Solutions to thread safety issues

    • The idea is to encapsulate multiple thread codes that operate on shared data. When a thread is executing these codes, other threads cannot participate in the operation. After all these codes are executed, other threads can participate in the operation.

    • In java, this problem can be solved with synchronized code blocks . (Or just add the synchronized modifier to the function)

    • The format of the synchronized code block:

     synchronized(对象)
    {
        需要被同步的代码
    }
  • Features of Sync:

    • The benefit of synchronization: it solves the problem of thread safety.

    • Disadvantages of synchronization: When there are a lot of threads, because each thread will judge the lock on synchronization, which is very resource-intensive and will virtually reduce the running efficiency of the program.

    • The premise of synchronization: there must be multiple threads and use the same lock.

  • Use synchronized code blocks to solve security problems Cases:

    • Demand: depositors, two, each deposit money in the bank, deposit 100 yuan each time, and deposit three times in total.
    • Ideas:

      1. Define a Cons (depositor) class and implement the Runnable interface;

      2. Review the run method in the Cons class and execute the action stored in the Bank class;

      3. Lock the storage action, and only one customer can deposit money at a time.

      4. Create two threads and start the threads.

    • Code:
class Bank
{
    private int sum;
    public void add(int num)
    {   
        synchronized(this)//保证每次只有一个线程在调用
        {
            sum+=num;
            System.out.println("sum="+sum);
        }
    }
}
//实现Runnable接口
class Cons implements Runnable
{
    Bank b=new Bank();
    //复写Runnable中的run方法。
    public void run()
    {
        for(int x=0;x<3;x++)
        b.add(100);
    }
}
class BankDemo 
{
    public static void main(String[] args) 
    {
        //把资源进行封装,传入给线程
        Cons c=new Cons();
        //创建两个线程
        Thread t1=new Thread(c);
        Thread t2=new Thread(c);
        //开启线程
        t1.start();
        t2.start();
    }
}
  • Output result:

5. Singleton mode under multi-threading

  • There is no security problem in the hungry Chinese style, because there is no situation where multiple threads operate together on data.

  • Lazy-style has a security problem, which can be solved by using synchronous functions.

    • Code:
class Single
{
    private Single(){}
    private static Single s=null;
    public static Single getInstance()
    {
        //第一次判断,提高了效率,若对象已存在就不用判断锁了
        if(s==null)
        {
            //保证每次只有一个线程在调用
            synchronized(Single.class)
            {
                if(s==null)
                    s=new Single();
            }
        }
        return s;
    }
}

6. Deadlock

  • Definition: Multiple threads are blocked at the same time, one or all of them are waiting for a resource to be released. Since the thread is blocked indefinitely, it is impossible for the program to terminate normally.

  • Cause of deadlock:

    1. Because of insufficient system resources.
    2. The order in which the processes are running and advancing is not appropriate.
    3. Improper allocation of resources, etc.
  • There are four necessary conditions for a deadlock to occur:

    1. Mutual exclusion condition: A resource can only be used by one process at a time.
    2. Request and hold condition: When a process is blocked by requesting a resource, it will hold on to the obtained resource.
    3. No deprivation condition: The resources that the process has obtained cannot be forcibly deprived until the resources are used up.
    4. Circular waiting condition: a cyclic waiting resource relationship is formed between several processes.
  • Sample code:

class Test implements Runnable
{
    //flag是标识
    private boolean flag;
    Test(Boolean flag)
    {
        this.flag=flag;
    }
    public void run()
    {
        if(flag)
        {
            while (true)
            {
                //锁a
                synchronized(MyLock.locka)
                {
                    System.out.println(Thread.currentThread().getName()+"……if lacka……");
                }
                //锁b
                synchronized(MyLock.lockb)
                {
                    System.out.println(Thread.currentThread().getName()+"……if lackb……");
                }
            }           
        }
        else 
        {
            while (true)
            {
                //锁b
                synchronized(MyLock.lockb)
                {
                    System.out.println(Thread.currentThread().getName()+"……else lackb……");
                }
                //锁a
                synchronized(MyLock.locka)
                {
                    System.out.println(Thread.currentThread().getName()+"……else lacka……");
                }
            }
        }       
    }
}
class MyLock
{
    public static final Object locka=new Object();
    public static final Object lockb=new Object();
}
class DeadLockDemo 
{
    public static void main(String[] args) 
    {
        Test t1=new Test(true);
        Test t2=new Test(false);
        //创建线程
        Thread d1=new Thread(t1);
        Thread d2=new Thread(t2);
        //开启线程
        d1.start();
        d2.start();
    }
}

7. Inter-thread communication

  • The methods involved in the wait/wake mechanism:
    1. wait(): Keep the thread in a frozen state, and the thread that is waited will be stored in the thread pool.
    2. notify(): wake up a thread in the thread pool (any one is possible)
    3. notifyAll(): Wake up all threads in the thread pool.
  • The difference between wait and sleep:
    1. wait can specify a time or not, and sleep must specify a time.
    2. In synchronization, execution rights and locks are handled differently to the CPU.
      1. wait: Release the execution right and release the lock.
      2. sleep: Release the execution right without releasing the lock.
  • Example (producer-consumer problem):
    • Code:
class Resource
{
    private String name;
    private String sex;
    private boolean flag=false;
    public synchronized void set(String name,String sex)
    {
        //flag为true时,线程t1冻结,等待唤醒
        if(flag)
            try
            {
                this.wait();    
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        this.name=name;
        this.sex=sex;
        flag=true;
        notify();
    }
    public synchronized void out()
    {
        //flag为false时,线程t2冻结,等待唤醒
        if(!flag)
            try
            {
                this.wait();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            System.out.println(name+"……"+sex);
            flag=false;
            notify();
    }
}
//输入,实现Runable接口
class Input implements Runnable
{
    Resource r;
    Input(Resource r)
    {
        this.r=r;
    }
    public void run()
    {
        int x=0;
        while(true)
        {
            if (x==0)
            {
                r.set("小明","男");
            }
            else
            {
                r.set("小红","女");
            }
            x=(x+1)%2;
        }

    }
}
//输出,实现Runnable接口
class Output implements Runnable
{
    Resource r;
    Output(Resource r)
    {
        this.r=r;
    }
    public void run()
    {
        while(true)
        {
            r.out();
        }
    }
}
class ResourceDemo
{
    public static void main(String[] args) 
    {
        //封装资源
        Resource r=new Resource();
        //创建任务
        Input in=new Input(r);
        Output out=new Output(r);
        //创建线程
        Thread t1=new Thread(in);
        Thread t2=new Thread(out);
        //开启线程
        t1.start();
        t2.start();
    }
}
  • Output result:
    write picture description here

8. New features of JDK1.5

  • After JDK1.5, synchronization and locks are encapsulated into objects, and the implicit way of operating locks is defined into the object, turning implicit actions into explicit actions.
    • Lock interface: appears to replace the synchronized code block or synchronized function, turning the implicit operation of synchronization into an explicit lock operation. At the same time, it is more flexible and can add multiple sets of monitors to one lock.
    • lock(): Acquires the lock.
    • unlock(): Release the lock. In order to prevent exceptions, the lock cannot be closed, so the closing action of the lock should be placed in finally.
    • Condition interface: Appears to replace the wait, notify, notifyAll methods in Object. These monitor methods are individually encapsulated and turned into Condition monitor objects, which can be combined with arbitrary locks.
      • The await method in the Condition interface corresponds to the wait method in Object.
      • The signal method in the Condition interface corresponds to the notify method in Object.
      • The signalAll method in the Condition interface corresponds to the notifyAll method in Object.
  • Example (Producer, multi-consumer problem: one Lock, two Conditions)
    • Code:
import java.util.concurrent.locks.*;
class Resource
{
    private String name;
    private int count=1;
    private boolean flag=false;

    //创建一个锁对象
    Lock lock=new ReentrantLock();

    //通过已有的锁获取该锁上的监视对象
    Condition pro_con=lock.newCondition();
    Condition con_con=lock.newCondition();
    public void set(String name)
    {
        //获取锁
        lock.lock ();
        try
        {
            while(flag)
            {
                try
                {
                    //生产者监视器冻结
                    pro_con.await();
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
                this.name=name+count;
                count++;
                System.out.println(Thread.currentThread().getName()+"……生产"+this.name);
                flag=true;
                //唤醒消费者监视器
                con_con.signal();
        }
        finally
        {
            //释放锁
            lock.unlock();
        }
    }
    public void out()
    {
        //获取锁
        lock.lock();
        try
        {
            while(!flag)
            {
                try
                {
                    //消费者监视器冻结
                    con_con.await();
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+"…… 消费"+name);
            flag=false;
            //唤醒生产者监视器
            pro_con.signal();
        }
        finally
        {
            //释放锁
            lock.unlock();
        }
    }
}
//输入
class Producer implements Runnable
{
    Resource r;
    Producer(Resource r)
    {
        this.r=r;
    }
    public void run()
    {
        while(true)
        {
            r.set("烤鸭");
        }
    }
}
//输出
class Consumer implements Runnable
{
    Resource r;
    Consumer(Resource r)
    {
        this.r=r;
    }
    public void run()
    {
        while(true)
        {
            r.out();
        }
    }
}
class ProducerConsumerDemo2
{
    public static void main(String[] args) 
    {
        Resource r=new Resource();
        Producer pro=new Producer(r);
        Consumer con=new Consumer(r);
        Thread t1=new Thread(pro);
        Thread t2=new Thread(pro);
        Thread t3=new Thread(con);
        Thread t4=new Thread(con);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
  • Output result:

Guess you like

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