java多线程简单总结

创建一个子线程的三种方式

  1. 继承Thread 重写 void run(),然后start()
  2. 实现runable 的 void run(),通过Thread(Runable)构造,或者线程池execute(Runable),submit(Runable)
  3. 实现callable 的 T call() ,通过Thread(Callable)构造,或者线程池submit(Callable)

继承Thread 与 Thread(Runable)的区别

继承Thread,只能在Thread层面去控制变量。
而通过Thread(Runable)的方式,可以在Runable层面控制变量。
比如,使用Runable的一个实例,构造多个Thread,虽然这些Thread处在不同的线程,却共享同一个runable的成员变量。
该博主解释的很好,原链接

Thread生命周期

Thread 内部枚举state

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 <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * 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;
    }

Thread对象共有6种状态:NEW(新建),RUNNABLE(运行),BLOCKED(阻塞),WAITING(等待),TIMED_WAITING(有时间的等待),TERMINATED(终止);状态转换如下:
null

sleep join wait 区别

sleep 和 wait 调用的native方法,join调用wait,没有研究过native源码,在网上搜了一些资料,下面是一些个人认为比较正确的。
sleep(n>0) 释放自己的cpu占用,进入就绪状态,等待1000毫秒后参与cpu竞争。
sleep(0)重新进行cpu竞争,自己也参与竞争。场景比如:普通优先级但是占用时间长的线程,在自己时间片进入堵塞,让位给高优先级的线程。
sleep 不会释放锁
sleep详情
wait(0)与wait()相同 与wait(n>0)不同。
wait()使 当前线程 进入等待状态,等待notify()或notifyall()唤醒,进入就绪状态(不是运行!!)。
wait(n>0)使 当前线程 进入等待状态,等待notify()或notifyall()唤醒,或超过超时时间自动进入就绪状态(不是运行!!)。
wait会释放锁

wait详情

举例:AB两个线程,持有对a的锁。AB同时开始,A获取到a的锁,然后进入wait(),此时A会释放掉a的锁,B获得a的锁,
此时注意了!
如果 B 什么不做,线程结束后,锁自动释放,A会获得锁继续执行。
如果 B 执行wait(),A会获得锁继续执行。
如果 B 执行sleep(10000),AB都会进入就绪状态,在10秒内,B不会竞争cpu资源一直处于就绪状态。A没有获得a的锁,也会一直处于就绪状态。

join方法 调用 wait 方法实现
功能类似
join() 如果join的线程存活,则当前线程一直处于等待状态,直到join的线程不再存活。
join(n>0)如果join的线程存活,让当前线程进入等待状态,直到被唤醒,或在n毫秒后进入就绪状态。

Thread 常用方法

Thread start与run方法区别

start方法,使用了native方法start0(),启动一个新线程,执行run()。
直接调用run(),失去了线程的意义,和普通对象调用方法相同。所以尽量不要直接调用run()(因此不知道为什么run()是public?因为native方法实现调用的时候必须是public?)

runable 与 callable 区别

runable 没有返回值。不可向上抛异常,内部消化。异常处理方式,1try catch 2Exceptionhandler

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

callable可以返回结果。可以向上抛异常。异常处理,主线程中 future.get();

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

线程池方法submit与execute区别

线程池继承自 AbstractExecutorService,看一下源码。
submit有三个方法 submit(Runable)submit(Runable,T)submit(Callable)
execute只有一个方法 execute(Runable)

— submit

/**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }
  /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }
 /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

— execute (由子类继承实现 这里贴ThreadPoolExecutor的源码)

 public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

总结:
execute参数Runable
submit参数可以Runable、Callable
submit最终还是调用execute。

submit核心内容是FutureTask

此类实现了runableFuture,而runableFuture继承了runable和future类。

不难理解futureTask要做的工作,不仅实现了线程要做的方法(runable),并且获取结果返回(future)。

看代码: future的run()方法。

 public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;	//callable 要做的事情
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call(); // 执行call方法 获取结果
                    ran = true;
                } catch (Throwable ex) {	//捕获异常
                    result = null;
                    ran = false;
                    setException(ex);	//future方法 保存异常
                }
                if (ran)
                    set(result);		//future方法 保存结果
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

submit的工作:将参数封装了一个futureTask作为execute的参数。

  1. 封装过程中,将runable和指定结果 转换成了callable。

  2. 然后将转换成的callable在 futureTask的run方法中执行,获取结果或异常,利用future接口方法保存结果或异常。

  3. 通过future接口get方法。返回结果和异常。

所以,提交子线程任务时,首先根据需要选择runable或callable。

如果是runable,并且不需要返回特定结果,直接调用execute性能比较高。(也可以使用submit,应该是submit的兼容,跟直接调用execute效果一样,不过做了很多无用功。)

如果是callable。调用submit。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伞_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值