JUC series - JUC entry and multi-threaded concurrency


foreword

As JAVA programmers become more and more volume, now they need to continue to learn deeper knowledge to achieve volume capital. This system tutorial mainly introduces JUC. In this chapter, let us get to know it from the beginning. As a senior JAVA programmer, you must know what is JUC, what it is used for, and how to use it. This is also one of the must-ask techniques in interviews with major manufacturers.


1. Introduction to JUC

1. From which great god?

  • JUC was designed and developed by Doug Lea, a university teacher in the United States.
  • Doug Lea serves on the faculty of the Department of Computing at the State University of New York at Oswego.
  • Doug Lea is a member of JCP (JAVA Community Project).
  • Let us admire the appearance of the Great God and learn more from the Great God.
    insert image description here

2. What is JUC?

  • JUC is the abbreviation of java.util.concurrent package in JDK (Chinese abbreviation: concurrent toolkit), which contains three packages:
    • java.util.concurrent
    • java.util.concurrent.atomic
    • java.util.concurrent.locks
  • yesJDK1.5 released in October 2004Added basic APIs for writing concurrency.
  • Currently JUC generally refers to JAVA multi-threaded development technology.

2. What problems does JUC mainly solve?

The main problems that JUC solves are:High cohesion and low couplingThe premise,threadhowoperate Resource classCan achieve high concurrency and high availability?

先来学习一下几个基本概念

1. Process, thread

  • process:
    • The smallest unit that an operating system can deploy.
    • Have your own independent space.
    • For example: QQ, CF, and Wangwang running in the system are all independent processes.
  • thread:
    • A thread is the smallest unit that can be allocated in a process.
    • A process can contain multiple threads.
    • For example: 360 Guard contains many functions, such as anti-virus, downloading software, etc., which are different threads in a process.

2. Concurrent and parallel

  • concurrent:
    • The same function is called at the same time.
    • The same program is called at the same time.
  • parallel:
    • Different functions are called simultaneously.
    • Different programs are called simultaneously.

JUC就是解决多线程执行中遇到的问题,所以我们再来看一下JAVA里是怎么创建线程和操作线程的

3. The way JAVA creates threads (simulating three thread implementation methods)

Simulate a multi-threaded demand: train conductors A, B, and C sell 10 tickets for a train at the same time until they are sold out.

1) Inherit the Thread class (primary usage of threads)

使用JUC中的Lock实现不现线程对同一资源的操作
conductor class:

package com.juc.study;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 火车售票员
 */
public class TrainConductor extends Thread {
    
    

    public TrainConductor() {
    
    
    }

    public TrainConductor(String name) {
    
    
        super(name);
    }

    /**
     * 售票
     */
    public void saleTickets() {
    
    
        // JUC中的锁,是轻量级的锁,实现类是可重入锁,
        // 意味着只要有人释放锁,另外一个人就可以重新拿到锁并执行。
        Lock lock = new ReentrantLock();
        lock.lock();
        try {
    
    
            if(Ticket.nums > 0) {
    
    
                System.out.println(Thread.currentThread().getName() + "\t 卖出第:" + (Ticket.nums--) + "张,\t 还剩下:" + Ticket.nums);
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            lock.unlock();
        }
    }

    @Override
    public void run() {
    
    
        for(int i = 70; i > 0; i--) {
    
    
            saleTickets();
        }
    }
}

Train ticket category:

package com.juc.study;

public class Ticket {
    
    

    public static int nums = 10;

}

Execution class:

import com.juc.study.Ticket;
import com.juc.study.TrainConductor;

public class TestJUC {
    
    


    public static void main(String[] args) {
    
    
        // 新建三个售票员
        TrainConductor trainConductorA = new TrainConductor("A");
        TrainConductor trainConductorB = new TrainConductor("B");
        TrainConductor trainConductorC = new TrainConductor("C");

        // 开始售票
        trainConductorA.start();
        trainConductorB.start();
        trainConductorC.start();
    }

}

Results of the:

A	 卖出第:9张,	 还剩下:8
C	 卖出第:8张,	 还剩下:7
B	 卖出第:10张,	 还剩下:8
C	 卖出第:6张,	 还剩下:5
C	 卖出第:4张,	 还剩下:3
A	 卖出第:7张,	 还剩下:6
C	 卖出第:3张,	 还剩下:2
C	 卖出第:1张,	 还剩下:0
A	 卖出第:2张,	 还剩下:1
B	 卖出第:5张,	 还剩下:4

2) Implement the Runnable interface (primary usage of threads)

与继承Thead类的写法有点区别,大家注意观察
conductor class:

package com.juc.study;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 售票员类
 */
public class TrainConductorRunnable implements Runnable{
    
    

    /**
     * 售票
     */
    public void saleTickets() {
    
    
        // JUC中的锁,是轻量级的锁,实现类是可重入锁,
        // 意味着只要有人释放锁,另外一个人就可以重新拿到锁并执行。
        Lock lock = new ReentrantLock();
        lock.lock();
        try {
    
    
            if(Ticket.nums > 0) {
    
    
                System.out.println(Thread.currentThread().getName() + "\t 卖出第:" + (Ticket.nums--) + "张,\t 还剩下:" + Ticket.nums);
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            lock.unlock();
        }
    }

    @Override
    public void run() {
    
    
        for(int i = 70; i > 0; i--) {
    
    
            saleTickets();
        }
    }
}

Train ticket category (no change):

package com.juc.study;

public class Ticket {
    
    

    public static int nums = 10;

}

Execution class:

import com.juc.study.Ticket;
import com.juc.study.TrainConductor;
import com.juc.study.TrainConductorRunnable;

public class TestJUC {
    
    


    public static void main(String[] args) {
    
    
        // 新建三个售票员
        TrainConductorRunnable trainConductorA = new TrainConductorRunnable();
        TrainConductorRunnable trainConductorB = new TrainConductorRunnable();
        TrainConductorRunnable trainConductorC = new TrainConductorRunnable();

        // 新建三个线程
        Thread t1 = new Thread(trainConductorA, "A");
        Thread t2 = new Thread(trainConductorB, "B");
        Thread t3 = new Thread(trainConductorC, "C");

        // 开始售票
        t1.start();
        t2.start();
        t3.start();
    }

}

Results of the:

A	 卖出第:9张,	 还剩下:7
C	 卖出第:8张,	 还剩下:7
A	 卖出第:7张,	 还剩下:6
B	 卖出第:10张,	 还剩下:7
A	 卖出第:5张,	 还剩下:4
C	 卖出第:6张,	 还剩下:5
A	 卖出第:3张,	 还剩下:2
B	 卖出第:4张,	 还剩下:3
A	 卖出第:1张,	 还剩下:0
C	 卖出第:2张,	 还剩下:1

3) Inner class approach (intermediate usage of threads)

使用内部类实现是不需要继承Thread类或实现Runnable接口,大家仔细看

Train conductor class:

package com.juc.study;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 火车售票员(采用内部类的形式实现)
 */
public class TrainConductorInner {
    
    

    /**
     * 售票
     */
    public void saleTickets() {
    
    
        // JUC中的锁,是轻量级的锁,实现类是可重入锁,
        // 意味着只要有人释放锁,另外一个人就可以重新拿到锁并执行。
        Lock lock = new ReentrantLock();
        lock.lock();
        try {
    
    
            if(Ticket.nums > 0) {
    
    
                System.out.println(Thread.currentThread().getName() + "\t 卖出第:" + (Ticket.nums--) + "张,\t 还剩下:" + Ticket.nums);
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            lock.unlock();
        }
    }

}

Train ticket category (no change):

package com.juc.study;

public class Ticket {
    
    

    public static int nums = 10;

}

Execution class:

import com.juc.study.Ticket;
import com.juc.study.TrainConductorInner;

public class TestJUC {
    
    

    public static void main(String[] args) {
    
    
    
        Thread t1 = new Thread("A") {
    
    
            @Override
            public void run() {
    
    
                for(int i = 70; i > 0; i--) {
    
    
                    TrainConductorInner a = new TrainConductorInner();
                    a.saleTickets();
                }
            }
        };
        t1.start();

        Thread t2 = new Thread("B") {
    
    
            @Override
            public void run() {
    
    
                for(int i = 70; i > 0; i--) {
    
    
                    TrainConductorInner b = new TrainConductorInner();
                    b.saleTickets();
                }
            }
        };
        t2.start();

        Thread t3 = new Thread("C") {
    
    
            @Override
            public void run() {
    
    
                for(int i = 70; i > 0; i--) {
    
    
                    TrainConductorInner c = new TrainConductorInner();
                    c.saleTickets();
                }
            }
        };
        t3.start();
    }

}

4) Implemented using lamada expressions (advanced usage and the most commonly used method in enterprises)

lamada表达式写完之后有点长,如果看不懂可以给它格式化一下

Train conductor class (still using the inner class, no change):

package com.juc.study;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 火车售票员(采用内部类的形式实现)
 */
public class TrainConductorInner {
    
    

    /**
     * 售票
     */
    public void saleTickets() {
    
    
        // JUC中的锁,是轻量级的锁,实现类是可重入锁,
        // 意味着只要有人释放锁,另外一个人就可以重新拿到锁并执行。
        Lock lock = new ReentrantLock();
        lock.lock();
        try {
    
    
            if(Ticket.nums > 0) {
    
    
                System.out.println(Thread.currentThread().getName() + "\t 卖出第:" + (Ticket.nums--) + "张,\t 还剩下:" + Ticket.nums);
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            lock.unlock();
        }
    }

}

Train ticket category (no change):

package com.juc.study;

public class Ticket {
    
    

    public static int nums = 10;

}

Execution class (lamada expression is used here):

import com.juc.study.Ticket;
import com.juc.study.TrainConductorInner;

public class TestJUC {
    
    

    public static void main(String[] args) {
    
    
        new Thread(()->{
    
    for(int i = 70; i > 0; i--){
    
    TrainConductorInner a = new TrainConductorInner(); a.saleTickets();}}, "A").start();
        new Thread(()->{
    
    for(int i = 70; i > 0; i--){
    
    TrainConductorInner b = new TrainConductorInner(); b.saleTickets();}}, "B").start();
        new Thread(()->{
    
    for(int i = 70; i > 0; i--){
    
    TrainConductorInner c = new TrainConductorInner(); c.saleTickets();}}, "C").start();
    }

}


Summarize

The most important sentence:Under the premise of high cohesion and low coupling, it is the task of JUC to achieve the effect of high concurrency and high availability of thread operation resource classes.
The introduction to JUC is here. You should have a little feeling about JUC here. Is it fun? The following chapters will be more exciting, so stay tuned. . . . . .

Guess you like

Origin blog.csdn.net/yezhijing/article/details/128080409