【Java】 多线程|线程池|计时器|并发与并行|线程生命周期

(一)、多线程

1、线程创建方式:

(1)继承Thread类

 

class PrimeThread extends Thread {
    long minPrime;
    PrimeThread(long minPrime) {
        this.minPrime = minPrime;
    }

    public void run() {
      . . .
    }
}

PrimeThread p = new PrimeThread(143);
p.start();

 

编码简单,但存在单继承的局限性,不能继承其他类,不便于扩展。

重写的Run方法不能返回执行结果。

不适合需要返回执行结果的场景。

(2)实现Runnble接口

 

class PrimeRun implements Runnable {
    long minPrime;
    PrimeRun(long minPrime) {
        this.minPrime = minPrime;
    }

    public void run() {
      . . .
    }
}

PrimeRun p = new PrimeRun(143);
new Thread(p).start();

 

线程任务类实现接口,便于扩展,但编程多一层包装对象。

重写的Run方法不能返回执行结果。

不适合需要返回执行结果的场景。

(3)实现Callable接口

 

class PrimeCallable implements Callable<V>{
    long minPrime;
    PrimeCallable (long minPrime) {
        this.minPrime = minPrime;
    }

    public V call() throws Exception{
      . . .
        return V;
    }
}

Callable<V> call = new PrimeCallable(143);
FutureTask<V> target = new FutureTask<T>(call);
new Thread(target ).start();
V result = target.get();

 

通过实现Callable接口再封装成FutureTask对象来创建任务对象。

线程任务类实现接口,扩展性强,可以在线程执行完毕后通过FutureTask返回执行结果。

编码更加复杂(有点牵强)。

2、线程常用方法

(1)final String getName()  

Returns this thread's name.(获取线程名称)

(2)final void setName(String name)  

Changes the name of this thread to be equal to the argument name.(设置线程名称)

(3)static Thread currentThread()

Returns a reference to the currently executing thread object.(获取当前线程对象)

没必要为线程设置名称,默认名字即可。

3、线程安全问题

多个线程同事操作同一个共享资源的时候可能出现业务安全问题,称为线程安全问题。

线程同步实现使用加锁,把共享资源上锁,让多线程实现先后依次访问。

(1)同步代码块

synchronized(同步锁对象){操作共享资源的代码}

代码块内容被加锁,代码块执行完毕后自动解锁。

同步锁对象理论上可以是任意唯一对象,但存在每个对象创建都会受与锁对象局限。

实例方法推荐使用this作为锁对象,

静态方法推荐使用字节码(类名.call)作为锁对象。

(2)同步方法

在方法定义时使用synchronized修饰即可。

算是隐式锁对象,将整个方法作为同步代码块。

同步方法默认使用this和类名.call作为锁对象

(3)Lock锁

使用Lock的实现类ReentrantLock创建。

 class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() {
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock();
     }
   }
 }

比synchronized丰富,更加强大。

4、线程通信

通常通过共享一个数据的方式实现,根据数据来决定等待自己或是唤醒别人。

如生产者与消费者模型:生产者线程负责生产数据,消费者线程负责消费生产者生产的数据。

一般要求:生产者线程生产完后唤醒消费者,等待自己,消费者消费完后,唤醒生产者,等待自己。

Object类的等待和唤醒方法:

void wait()

void notify()

void notifyall()

注意:上诉方法应该使用当前同步锁对象进行调用。

(二)、线程池

(1)Interface ExecutorService

通常使用实现类Class ThreadPoolExecutor来创建线程池。

ThreadPoolExecutor(int corePoolSize,               //指定线程池数量(核心线程)

          int maximumPoolSize,            //指定线程池最大数量(临时线程=最大数量-核心线程)     

          long keepAliveTime,               //指定临时线程存活时间    

          TimeUnit unit,                  //指定存活时间单位(秒,分,时,天)

          BlockingQueue<Runnable> workQueue,    //指定任务队列

          ThreadFactory threadFactory,            //指定使用哪个线程工厂创建线程

          RejectedExecutionHandler handler)       //指定线程忙并且任务队列满后的策略

临时线程必须是在核心线程占用中并且任务队列满后出现新任务才会创建临时线程。(超负荷的时候才考虑创建临时线程)

RejectedExecutionHandler 策略必须是在核心线程和临时线程都在占用中,并且任务队列满后出现新任务时才会使用。

class PrimeRun implements Runnable {
    long minPrime;
    PrimeRun(long minPrime) {
        this.minPrime = minPrime;
    }

    public void run() {
              . . .
    }
}
ExecutorService pool = new ThreadPoolExecutor(3,5,
        6,TimeUnit.SECONDS, new ArrayBlockingQueue<>(5),
        Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
PrimeRun p = new PrimeRun(143);
pool.execute(p);   

使用默认线程工厂并且使用默认新任务拒绝策略。

新任务拒绝策略

1.ThreadPoolExecutor.AbortPolicy()       //丢弃任务并抛出RejectedExecutionException异常,默认策略。

2.ThreadPoolExecutor.DiscardPolicy()        //丢弃任务,但不抛异常,不推荐

3.ThreadPoolExecutor.DiscardOldestPolicy()   //抛弃队列中等待最久的任务,然后把新任务加入队列中

4.ThreadPoolExecutor.CallerRunsPolicy()     //由主线程负责对调用任务的run()方法,从而绕过线程池直接执行

ExecutorService的常用方法

1  void execute(Runnable command)

Executes the given command at some time in the future.(向线程池任务队列添加任务)

2  Future<?> submit(Runnable task)

Submits a Runnable task for execution and returns a Future representing that task.(向线程池任务队列添加任务并返回Future 未来任务对象的父类接口可以使用FutureTask<V> 来接受)
3  void shutdown()
Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.(等待任务执行完毕后关闭线程池)
4  List<Runnable> shutdownNow()
Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting(立即关闭,停止正在执行的任务,并返回队列中未执行的任务)

(2)Class Executors

(1)static ExecutorService newCachedThreadPool()
Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available.(线程数量随着任务增加而增加,如果线程任务执行完毕并且空闲一段时间则会被回收掉)
注意:允许请求的任务队列长度是Integer.MAX_VALUE,可能出现OOM(全称“Out Of Memory”,翻译成中文“内存用完了”,)错误(java.lang.OutOfMemoryError)

(2)static ExecutorService newFixedThreadPool(int nThreads)

Creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue.(创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程代替它)
注意:允许请求的任务队列长度是Integer.MAX_VALUE,可能出现OOM(全称“Out Of Memory”,翻译成中文“内存用完了”,)错误(java.lang.OutOfMemoryError)
(3)static ExecutorService newSingleThreadExecutor()
Creates an Executor that uses a single worker thread operating off an unbounded queue.(创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程)
注意:创建的线程数量最大上线是Integer.MAX_VALUE,可能出现OOM(全称“Out Of Memory”,翻译成中文“内存用完了”,)错误(java.lang.OutOfMemoryError)
(4)static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
Creates a thread pool that can schedule commands to run after a given delay, or to execute periodically.(创建一个线程池,可以实现给定的延迟后执行任务,或者定期执行任务)
注意:创建的线程数量最大上线是Integer.MAX_VALUE,可能出现OOM(全称“Out Of Memory”,翻译成中文“内存用完了”,)错误(java.lang.OutOfMemoryError)
 
注意:Executors的底层其实也是基于线程池的实现ThreadPoolExecutor创建线程池对象的。

(三)、定时器

(1)Class Timer

构造方法:

Timer() 
Creates a new timer.

周期调度方法

void schedule(TimerTask task, long delay, long period)
Schedules the specified task for repeated fixed-delay execution, beginning after the specified delay.(开启一个定时器,按照计划处理TimerTask任务)
特点:
1、Timer是单线程,处理多个任务按照顺序执行,存在延时与设置定时器的时间有出入。
2、可能因为其中某一个任务异常使Timer线程死掉,从而影响后续任务执行。

(2)Interface ScheduledExecutorService

ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
pool.scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        //定时任务
        ...
    }
}, 2, 2, TimeUnit.SECONDS); //延迟多久时间后开始执行,周期延迟时间,延迟时间单位。

使用Executors的方法创建线程池对象。

static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

使用ScheduledExecutorService的周期调度方法

ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
Submits a periodic action that becomes enabled first after the given initial delay, and subsequently with the given delay between the termination of one execution and the commencement of the next.
特点:
基于线程池,某个任务的执行情况不会影响其他定时任务的执行。
 

(四)、并发与并行

正在运行的程序就是一个独立的进程,线程是属于进程的,多个线程其实是并发与并行同时进行的。

CPU同时处理线程的数量是有限的,所以会轮询为系统的每个线程服务,由于CPU切换的速度很快,感觉是同时执行,这就是并发。

CPU核数不同,多核同时执行多个任务,这就是并行。

并发:CPU轮询的执行线程。

并行:同一时间同时执行。

(五)、线程生命周期

   public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called {@code Object.wait()}
         * on an object is waiting for another thread to call
         * {@code Object.notify()} or {@code Object.notifyAll()} on
         * that object. A thread that has called {@code Thread.join()}
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }
NEW      线程新建状态
(New新建)线程刚被创建,但是并未启动。
RUNNABLE  可运行状态
(Runnable可运行)线程已经调用了start()等待CPU调度。
BLOCKED   Blocked锁阻塞状态
(Blocked锁阻塞)线程在执行的时候未竞争到锁对象,则该线程进入Blocked状态。
WAITING   无线等待状态
(Waiting无线等待)一个线程进入Waiting状态,另一个线程调用notify或者notifyAll方法才能够唤醒。
TIMED_WAITING  被终止状态
(Timed Waiting计时等待)通waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。带有超时参数的常用方法有Thread,sleep、Object.wait。
TERMINATED    计时等待状态
(Teminated被终止)因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。
截图来自网络。

 

posted @ 2022-03-29 02:03  Shuranima  阅读(61)  评论(0)    收藏  举报