Java多线程①——线程知识梳理

      多线程文章目录

  • 线程状态

       了解线程的状态是基础,理解其他内容更方便。

  • 线程常用方法

    注意wait/notify必须在同步代码块中执行;注意interrupt方法只是设置中断位;

    这些方法对新手来说一定要在实际操作中去体会细节。

 

  • Thread相关类和示例

  和thread相关的类有Runnable、Callable、Future、FutureTask等(简单的概念)

线程状态

 

  • 新建状态(New):新建线程对象
  • 就绪状态(Runnable) 调用start()方法
  • 运行状态(Running) 获得cpu的执行权限
  • (有人将阻塞分为三种,等待阻塞、同步阻塞和其他阻塞;个人觉得不利于理解线程的状态)
  • BLOCKED/WAITING/TIMED_WAITING
  • BLOCKED: 同步代码块/等待lock
  • WAITING:无限等待唤醒、没有超时时间的wait和join方法/locksupport.park()
  • TIMED_WAITING: 有时限的等待、包括sleep、wait(ts)、join(ts)、locksupport.parkNanos/parkUntil
  • 死亡状态(Dead) 线程执行完成或者异常退出

 

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;
}

 

 

线程常用方法 

// 睡眠,不释放控制权
TimeUnit.MINUTES.sleep(2);
//isAlive():线程处于“新建”状态时,线程调用isAlive()方法返回false。
//在线程的run()方法结束之前,即没有进入死亡状态之前,线程调用isAlive()方法返回true.
// yield():调用此方法的线程释放当前cpu的执行权、回到就绪状态.
// join():在A线程中调用B线程join()方法,表示当执行到此方法时,直到B线程执行完毕

//(过期)suspend()和resume() 暂停和重新开始,释放cpu执行权不释放锁;stop 已过期
//暂停和重开容易造成死锁,Stop无法释放资源

//wait() 和 notify() 等待和唤醒,释放cpu执行权和锁,Object方法
//wait/notify必须在同步代码块中执行,用于生成monitorenter 和 monitorexit指令
//同步块对象锁和执行wait的对象必须是同一个(否则IllegalMonitorStateException)
//监视器和对象锁(深入理解jvm)通俗地讲就是只有获取对obj的锁定之后才能用后面代码块中的代码访问obj资源,否则就无法访问obj也无法执行后面的代码,只能让线程停滞在那里等待其它线程解除对obj的锁定;

//interrupt 中断sleep、join和wait三者之一的阻塞继续执行。设置中断标志位为true;线程还是会执行完
//提前结束等待(抛出对应的中断异常InterruptedException: sleep interrupted)
//并不真正中断正在运行的线程,而只是发出中断请求,由线程在下一个合适的时刻中断自己。中断是取消线程最合理的方式。

Thread相关类和示例

Runnable、Callable、Future、FutureTask

继承Thread就不多说了,用的比较少;Runnable看上面的例子

Callable和Runnable差不多,不过实现方法时call,而且有返回值,不能交给Thread来包装运行

@Slf4j
public class RunnableDemo implements Runnable{

    @Override
    public void run() {
        log.info("-------10秒后大军来袭-----");
        synchronized (this){
            try {
                this.wait(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        log.info("-------keep going-----");
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new RunnableDemo());
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
@Slf4j
public class CallableDemo implements  Callable{

    String callName;

    public CallableDemo(String callName) {
        this.callName = callName;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建一个线程池
        ExecutorService pool = Executors.newFixedThreadPool(2);
        //创建两个有返回值的任务
        Callable c1 = new CallableDemo("A");
        Callable c2 = new CallableDemo("B");

        //执行任务并获取Future对象
        Future f1 = pool.submit(c1);
        Future f2 = pool.submit(c2);
        //从Future对象上获取任务的返回值,并输出到控制台
        log.info(">>>"+ f1.get().toString());
        log.info(">>>"+ f2.get().toString());
        //关闭线程池
        pool.shutdown();
    }

    @Override
    public Object call() throws Exception {
        log.info("-----执行call方法------");
        return  callName + ":success";
    }
}

 

Future是线程池的结果(泛型)类,在线程池Executor通过submit返回结果是Future;

用来查询Runnable或者Callable任务的执行情况,isDone,get等

FutureTask是一个类实现了RunnableFuture<V>,而RunnableFuture实现了Runnbale又实现了Futrue<V>这两个接口,另外它还能包装Runnale和Callable(通过适配器适配);

于是FutureTask既可以通过Thread包装来运行又可以交给ExecuteService来运行。然后获取任务执行情况

 

@Slf4j
public class FutureTaskDemo  {

    public static void main(String[] args) {
        // futureTask 执行Callable
        futureTaskTestCallRun();
        //futureTaskTestCallAsync();
        //futureTask 执行Runnable
        //futureTaskTestRunnable();
    }
   // 异步的futureTask被取消
    public static void futureTaskTestCallAsync(){
        CallableDemo callableDemo = new CallableDemo("测试futureTask");
        FutureTask futureTask1 = new FutureTask(callableDemo);
        System.out.println("线程状态:" + futureTask1.isDone());
        Thread thread = new Thread(futureTask1);
        thread.start();//异步
        try {
            System.out.println("cancel结果:" + futureTask1.cancel(true));
            System.out.println("线程状态:" + futureTask1.isDone());
            thread.join();
            System.out.println("执行结果:" + futureTask1.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    /**
      * @Author JackZhou
      * @Description  同步执行
     **/
    public static void futureTaskTestCallRun(){
        CallableDemo callableDemo = new CallableDemo("测试futureTask");
        FutureTask futureTask1 = new FutureTask(callableDemo);
        System.out.println("线程状态:" + futureTask1.isDone());
        futureTask1.run();//同步
        try {
            System.out.println("cancel结果:" + futureTask1.cancel(true));
            System.out.println("线程状态:" + futureTask1.isDone());
            System.out.println("执行结果:" + futureTask1.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    public static void futureTaskTestRunnable(){
        RunnableDemo runnableDemo = new RunnableDemo();
        FutureTask futureTask2 = new FutureTask(runnableDemo, Future.class);
        Thread thread = new Thread(futureTask2);
        thread.start();//异步
        try {
            System.out.println("线程状态:" + futureTask2.isDone());
            System.out.println("执行结果:" + futureTask2.get());
            System.out.println("线程状态:" + futureTask2.isDone());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

}
## futureTask state
cancel :取消方法,如图所示,同步异步执行之前都可以被cancel,执行结束以后不许;
NEW:表示这是一个新的任务,或者还没有执行完的任务,是初始状态。
COMPLETING:表示任务执行结束(正常执行结束,或者发生异常结束),但是还没有将结果保存到outcome中。是一个中间状态。
NORMAL:表示任务正常执行结束,并且已经把执行结果保存到outcome字段中。是一个最终状态。
EXCEPTIONAL:表示任务发生异常结束,异常信息已经保存到outcome中,这是一个最终状态。
CANCELLED:任务在新建之后,执行结束之前被取消了,但是不要求中断正在执行的线程,也就是调用了cancel(false),任务就是CANCELLED状态,这时任务状态变化是NEW -> CANCELLED。
INTERRUPTING:任务在新建之后,执行结束之前被取消了,并要求中断线程的执行,也就是调用了cancel(true),这时任务状态就是INTERRUPTING。这是一个中间状态。
INTERRUPTED:调用cancel(true)取消异步任务,会调用interrupt()中断线程的执行,然后状态会从INTERRUPTING变到INTERRUPTED。

Future也是执行的FutureTask的cancel方法;

FutureTask封装了计算任务,无论是提交给Thread执行,或者线程池执行,调用的都是FutureTask的run()。

尝试用cas修改FutureTask的运行状态为中断中INTERRUPTING或者已取消CANCELLED

如果获mayInterruptIfRunning为true,修改状态为中断INTERRUPTED

将当前线程状态设为已中断

 public boolean cancel(boolean mayInterruptIfRunning) {
    if (!(state == NEW &&
          UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
              mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
        return false;
    try {    // in case call to interrupt throws exception
        if (mayInterruptIfRunning) {
            try {
                Thread t = runner;
                if (t != null)
                    t.interrupt();
            } finally { // final state
                UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
            }
        }
    } finally {
        finishCompletion();
    }
    return true;
}
### 取消的方法主要在finishCompletion
private void finishCompletion() {
    // assert state > COMPLETING;
    for (WaitNode q; (q = waiters) != null;) {
        if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
            for (;;) {
                Thread t = q.thread;
                if (t != null) {
                    q.thread = null;
                    LockSupport.unpark(t);
                }
                WaitNode next = q.next;
                if (next == null)
                    break;
                q.next = null; // unlink to help gc
                q = next;
            }
            break;
        }
    }

    done();

    callable = null;        // to reduce footprint
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章