Java Concurrency and multithreading (3): thread pool, wake-up wait

First, wait wake-up mechanism

1 communication between threads

The concept : multiple threads working on the same resource, but the action (threaded task) is not treated the same.
For example: A thread is used to generate the buns, for thread B bun, buns can be understood as the same resource, the thread A and thread B process operation, is a production and a consumption, then between the threads A and thread B there is thread communication problems.
Here Insert Picture Description
(1) Why to handle communication between threads:
multiple threads execute concurrently, default CPU is randomly switching threads when multiple threads we need to work together to complete a task, and we want them to have the implementation of the law, It requires some coordination of communication between so many threads , in order to help us achieve an interoperable multi-threaded data.
(2) how to ensure the effective use of communication resources between threads:
that is, multiple threads operating the same data, to avoid competition for the same shared variables (efficiency first) . That is, we need to make sure each thread by means of effective use of resources. And this means that is - wait for the wake-up mechanism .

2, wait for the wake-up mechanism

This is a collaborative mechanism among multiple threads . We often talked about the thread is conceivable competition between threads (race), such as a lock to compete, but this is not the whole story, there will be a cooperation mechanism between threads . Like in the company that you and your colleagues, you may be present at the promotion of competition, but more often you more to work together to accomplish certain tasks.

(1) wait / notify is a collaborative mechanism among threads.
That is, a thread after a predetermined operation to enter the wait state (wait ()), waiting for their execution after the completion of the specified code then other threads its wake (the Notify ()) ; when there are multiple threads waiting, if necessary, use notifyAll () to wake up all waiting threads .

(2) wait for the wake-up method of
waiting wake-up mechanism is used to solve the problem of inter-thread communication , meaning to use the three methods are as follows:

  1. wait: the thread is no longer active, no longer involved in scheduling, enter the wait set (the set), so do not waste CPU resources, not to compete lock, then thread state that is WAITING. It is also waiting for another thread to perform a particular action, that is, " to inform (notify)" on this object to wait for the release of the thread from the wait set out to re-enter the scheduling queue (ready queue) in
  2. notify: The then select a thread (queue storage) notification object wait set in the release ; for example, the location of restaurants available, customers wait dining oldest first seated.
  3. notifyAll: All threads on the notification object wait set is released.

Note:
even if only to inform a waiting thread, the thread can not be notified immediately resume execution, because where it originally was interrupted in the synchronized block, but at the moment it no longer holds the lock, so she needs to try again to acquire the lock ( is likely to face competition from other threads), after the success of the implementation in place to recover after the original call wait method.

Summarized as follows:
(1) if they can get a lock, the thread becomes RUNNABLE status from WAITING state;
(2) Otherwise, set out from the wait, and into the entry set, the thread from WAITING state and becomes BLOCKED state

Call the object's lock wait and notify methods need to pay attention to the details

  1. wait and notify methods method must be called by the same lock object. Because: lock corresponding to the object can notify wake up to use the same lock on the
    thread after the wait as the method call.
  2. notify and wait method is a method belonging to the class of Object. Because: lock object can be any object, any object which belongs to the class are following the
    order of the Object class.
  3. Method and wait method must notify the synchronous or synchronous block function . Because: must be by calling the object lock these two square
    method.

3, the producer and consumer issues

Wait for the wake-up mechanism is actually a classic "producer-consumer" problem.

How to wait wake-up mechanism effective use of resources:
Baozi Pu thread production of buns, buns consumer food goods thread. When buns no time (buns state is false), food goods thread to wait Baozi Pu thread production dumplings
(ie dumplings state is true), and notifies food goods threads (lift food goods wait state), as it has been buns, then Baozi Pu thread into a wait state.

Next, eat goods thread can obtain further implementation of the case depends on the lock. If you eat the goods to get the lock, then the implementation of the action bun, bun eating (buns state is false), and notify the Baozi Pu thread (release wait state Baozi Pu), food goods thread into a wait . Baozi Pu thread can obtain further implementation of the case depends on the lock.
Here Insert Picture Description
Code demonstrates:

/**
 * 包子类
 * @author Mango
 */
public class BaoZi {

    String pi;
    String xian;
    boolean flag = false;

}
/**
 * 包子铺
 */
public class BaoZiShop extends Thread{

    private BaoZi baoZi;

    public BaoZiShop(String name, BaoZi baoZi) {
        super(name);
        this.baoZi = baoZi;
    }

    @Override
    public void run() {
        int count = 0;
        //造包子
        while(true) {
            synchronized (baoZi) {
                if (baoZi.flag) {
                    try {
                        baoZi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //没有包子 造包子
                System.out.println("包子铺开始做包子了");
                if(count %2 ==0) {
                    baoZi.pi = "冰皮";
                    baoZi.xian = "五仁";
                }else {
                    baoZi.pi = "薄皮";
                    baoZi.xian = "牛肉";
                }
                count++;

                baoZi.flag = true;
                System.out.println(baoZi.pi + baoZi.xian + "造好了");
                baoZi.notify();
            }
        }
    }
}
/**
 * 顾客
 * @author Mango
 */
public class Customer extends Thread{

    private BaoZi baoZi;

    public Customer(String name,BaoZi baoZi) {
        super(name);
        this.baoZi = baoZi;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (baoZi) {
                if(!baoZi.flag) {
                    //没包子
                    try {
                        baoZi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("顾客正在吃" + baoZi.pi + baoZi.xian + "包子");
                baoZi.flag = false;
                baoZi.notify();
            }
        }
    }

}

二、线程池

1、线程池思想概述

如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低
系统的效率,因为频繁创建线程和销毁线程需要时间

那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?在Java中可以通过与连接池类似的线程池来达到这样的效果。

2、线程池概念

线程池:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。

线程池原理如图:
Here Insert Picture Description
合理利用线程池能够带来三个好处:

  1. 降低资源消耗。减少了线程创建销毁的过程(j节约资源),每个工作线程都可以被重复利用,可执行多个任务。
  2. 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
  3. 提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内
    存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

3、线程池的使用

Java thread pool inside the top-level interface is java.util.concurrent.Executor, but is not a strict sense Executor thread
pools, but only one thread of execution tool. The real thread pool interface is a java.util.concurrent.ExecutorService.
Here Insert Picture Description
To configure a thread pool is more complex, especially for under the principle of the thread pool is not very clear, the likely configuration of the thread pool is not superior, thus providing a thread factory class inside java.util.concurrent.Executors some static factory to produce some common thread pool. The official recommended Executors engineering to create a thread pool object.

Executors class has created a thread pool as follows:
(1)public static ExecutorService newFixedThreadPool(int nThreads): Returns the thread pool object. (Created is bounded
away pool, which is the number of threads in the pool can specify the maximum number)

To get a thread pool ExecutorService objects, how to use it, here defines a method using a thread pool object as follows:
(1)public Future<?> submit(Runnable task): get one thread pool thread object , and perform the Future interface: used to record the thread after the task is completed the results produced. Creating and using a thread pool.

Use step thread pool thread object:

  1. Create a thread pool object.
  2. Runnable interface to create a subclass object. (Task)
  3. Submit Runnable interface subclass object. (Take task)
  4. Close the thread pool (usually not).

Runnable implementation class codes:

/**
 * 创建一个Runnable接口的实现类
 * @author Mango
 */
public class DomeRunnable implements Runnable {

    /**
     * 重写接口的run方法,设置线程任务
     */
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + "-->" + i );
        }
    }
}
/**
 * 测试线程池
 */
public class Demo2 {
    public static void main(String[] args) {
        //创建线程池
        ExecutorService service = Executors.newFixedThreadPool(2);
		//创建Runnable实例对象
        DomeRunnable runnable = new DomeRunnable();

		//从线程池中获取线程对象,然后调用runnable对象中的run()
        service.submit(runnable);
        service.submit(runnable);
    }
}
Published 47 original articles · won praise 18 · views 4860

Guess you like

Origin blog.csdn.net/qq_43605085/article/details/102301958