线程的基本方法

273 阅读7分钟

创建和运行线程

mport lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @Author blackcat
 * @version: 1.0
 * @description:线程创建
 */
@Slf4j
public class ThreadCreate {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //1、直接使用 Thread
        Thread thread = new Thread("thread") {
            @Override
            public void run() {
                log.info("thread  hello");
            }
        };
        thread.start();

        //2、使用 Runnable 配合 Thread
        // Java 8 以后可以使用 lambda 精简代码  Runnable target = () ->  log.info("runnable  hello");
        Runnable target = new Runnable() {
            @Override
            public void run() {
                log.info("runnable  hello");
            }
        };
        Thread runThread = new Thread(target, "runnable");
        runThread.start();

        //3、FutureTask 配合 Thread    有返回值
        FutureTask<Integer> task = new FutureTask<>(() -> {
            log.debug(" futureTask hello");
            int i = 100 / 0;
            return 100;
        });
        new Thread(task, "futureTask").start();


        try {
            //阻塞等待
            Integer number = task.get();
            log.info("task result :[{}]", number);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

常见API

方法名static功能说明注意
start()启动一个新线程,在新的线程运行run方法中的代码start方法只是让线程静茹就绪,里面代码不一定立刻运行(CPU时间片还没分给它).每个线程对象start方法只能调用一次,调用多次会出现illegalThreadStateException
run()新线程启动会调用的方法如果在构造Thread对象中传递了Runnable参数,则会调用默认的run方法.如果通过创建Thread的子类对象,会覆盖默认方法
join()等待线程运行结束
join(long n)等待线程运行结束,最多等n毫秒
getId()获取线程idid唯一
getName()获取线程名
serName(String)设置线程名
getPriority()获取线程优先级
setPriority(int)设置线程优先级
getStatus()获取线程状态java中线程状态有6种:NEW,RUNNABLE,BLOCKED WAITING,TIMED_WAITING,TERMINATED
isInterrupted()判断是否被打断不会清除打断标记
isAlive()线程是否存活
interrupt()打断线程如果被打断线程正在 sleep,wait,join 会导致被打断的线程抛出 InterruptedException,并清除打断标记 ;如果打断的正在运行的线程(或park),则会设置打断标记 ;
interrupted()static判断是否被打断会清除打断标记
currentThread()static获取当前正在执行的线程
sleep(long n)static让当前执行的线程休眠n毫秒,休眠时让出cpu的时间片给其他的线程
yield()static提示线程调度器用于测试和调试
stop()停止线程运行过时
suspend()挂起(暂停)线程运行过时
resume()恢复线程运行过时

start() 和 run()

import lombok.extern.slf4j.Slf4j;

/**
 * @Author blackcat
 * @version: 1.0
 * @description:Thread 的run()和start()的方法 (start()多次调用会报IllegalThreadStateException)
 */
@Slf4j
public class ThreadStartAndRun {


    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            log.debug("running");
        },"启动线程");
        //主线程调用方法
        thread.run();

        log.debug("thread before: [{}]' ",thread.getState());
        //启动线程 得到CPU时间片后 会调用run()
        thread.start();
        log.debug("thread after:[{}]",thread.getState());
        thread.start();
    }
}

sleep() and yield()

sleep

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

/**
 * @Author blackcat
 * @version: 1.0
 * @description: sleep:
 * 1. 调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)
 * 2. 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException(打断标记会清空)
 * 3. 睡眠结束后的线程未必会立刻得到执行
 * 4. 建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性(JDK1.5以后)
 * <p>
 * <p>
 * sleep的应用:
 * 在没有利用 cpu 来计算时,不要让 while(true) 空转浪费 cpu,这时可以使用 yield 或
 * sleep 来让出 cpu 的使用权给其他程序.适用于无锁状态
 * while(true) {
 * try {
 * Thread.sleep(50);
 * } catch (InterruptedException e) {
 * e.printStackTrace();
 * }
 * }
 *
 */
@Slf4j
public class ThreadSleep {

    public static void main(String[] agrs){
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(2);
                    //Thread.sleep(2000);
                } catch (InterruptedException e) {
                    log.info("interrupted");
                    e.printStackTrace();
                }
            }
        };

        t1.start();
        log.info("t1 state: [{}]", t1.getState());

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("t1 state: [{}]", t1.getState());
        t1.interrupt();

    }

}

yield

  1. 调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,然后调度执行其它线程

  2. 具体的实现依赖于操作系统的任务调度器

setPriority

/**
 * @Author blackcat
 * @version: 1.0
 * @description:
 * 线程优先级
 *      1.线程优先级会提示(hint)调度器优先调度该线程,但它仅仅是一个提示,调度器可以忽略它
 *      2.如果 cpu 比较忙,那么优先级高的线程会获得更多的时间片,但cpu闲时,优先级几乎没作用
 *
 */
public class ThreadPriority {

    public static void main(String[] args) {
        Runnable task1 = () -> {
            int count = 0;
            for (;;) {
                System.out.println("---->1 " + count++);
            }
        };
        Runnable task2 = () -> {
            int count = 0;
            for (;;) {
                //理论上线程1打印多
                // Thread.yield();
                System.out.println("              ---->2 " + count++);
            }
        };
        Thread t1 = new Thread(task1, "t1");
        Thread t2 = new Thread(task2, "t2");
        t1.setPriority(Thread.MIN_PRIORITY);
        t2.setPriority(Thread.MAX_PRIORITY);
        t1.start();
        t2.start();
    }
}

join() and join(long n)

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

/**
 * @Author blackcat
 * @version: 1.0
 * @description:join  等待线程结束
 */
@Slf4j
public class ThreadJoin {

    static int r = 0;

    static int r2 = 0;

    public static void main(String[] args) throws InterruptedException {
        join();
        join2();
        join3();
    }

    private static void join() throws InterruptedException {
        log.debug("开始");
        Thread t1 = new Thread(() -> {
            log.debug("开始");
            sleep(1);
            log.debug("结束");
            r = 10;
        });
        t1.start();
        t1.join();
        log.debug("结果为:[{}]", r);
        log.debug("结束");
    }


    private static void join2() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            sleep(1);
            r = 10;
        });
        Thread t2 = new Thread(() -> {
            sleep(2);
            r2 = 20;
        });
        long start = System.currentTimeMillis();
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        long end = System.currentTimeMillis();
        log.debug("r1: {} r2: {} cost: {}", r, r2, end - start);
    }


    private static void join3() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            sleep(2);
            r = 10;
        });
        long start = System.currentTimeMillis();
        t1.start();
        // 线程执行结束或是等待时间到了 join 结束
       // t1.join(3000);
        t1.join(1500);
        long end = System.currentTimeMillis();
        log.debug("r:{}  cost: {}", r,end - start);
    }

    private static void sleep(int i) {
        try {
            TimeUnit.SECONDS.sleep(i);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

interrupt

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.LockSupport;

/**
 * @Author blackcat
 * @create 2021/7/19 21:23
 * @version: 1.0
 * @description:线程打断方法 如果被打断线程正在 sleep,wait,join 会导致被打断的线程抛出InterruptedException,并清除打断标记;
 * 如果打断的正在运行的线程(或park),则会设置打断标记;
 */
@Slf4j
public class ThreadInterrupt {

    public static void main(String[] agrs) throws InterruptedException {
        interruptWait();
        interrupt();
        interruptPark();
    }

    private static void interruptPark() throws InterruptedException {
        Thread t3 = new Thread(() -> {
            log.info("park...");
            //当打断标记为true时 park阻塞无效     
            LockSupport.park();
            log.info("unpark...");
            //    log.debug("park 打断后:{}",Thread.interrupted());
            log.debug("park 打断后:{}", Thread.currentThread().isInterrupted());
            log.info("again park...");
            LockSupport.park();
            log.info("again unpark...");

        }, "t3");
        t3.start();
        Thread.sleep(200);
        t3.interrupt();

    }


    //打断正常的方法
    private static void interrupt() throws InterruptedException {
        Thread t2 = new Thread(() -> {
            while (true) {
                Thread current = Thread.currentThread();
                boolean interrupted = current.isInterrupted();
                //打断标记,线程自己判断
                if (interrupted) {
                    log.info(" 打断状态: {}", interrupted);
                    break;
                }
            }
        }, "t2");
        t2.start();
        Thread.sleep(1000);
        t2.interrupt();
    }

    //打断阻塞状态(sleep\wait\join)
    private static void interruptWait() throws InterruptedException {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                log.info("sleep");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    log.info("interrupted");
                    e.printStackTrace();
                }
            }
        };
        t1.start();

        Thread.sleep(1000);
        t1.interrupt();
        //打断阻塞状态会重置打断标记
        log.info("interrupt status:{}", t1.isInterrupted());
    }
}

关闭线程(两阶段终止模式

/**
 * @Author blackcat
 * @version: 1.0
 * @description:
 *
 *     Two Phase Termination(两阶段终止模式)
 *     在一个线程 T1 中如何“优雅”终止线程 T2?这里的【优雅】指的是给 T2 一个料理后事的机会。
 */
@Slf4j
public class TPTInterrupt {

    private Thread thread;

    public void start(){
        thread = new Thread(() -> {
           while(true){
               Thread currentThread = Thread.currentThread();
               boolean interrupted = currentThread.isInterrupted();
               if(interrupted){
                   log.info("料理后事,停止线程");
                   break;
               }
               try {
                   Thread.sleep(2000);
                   log.info("执行监控记录");
               } catch (InterruptedException e) {
                   currentThread.interrupt();
                   e.printStackTrace();
               }
           }
        },"监控线程");
        thread.start();
    }

    public void stop() {
        log.info("打断");
        thread.interrupt();
    }

    public static void main(String[] agrs) throws InterruptedException {
        TPTInterrupt t = new TPTInterrupt();
        t.start();
        Thread.sleep(3500);
        t.stop();

    }
}

/**
 * @Author blackcat
 * @version: 1.0
 * @description: 保证只启动一个监控线程
 */
@Slf4j
public class TPTInterrupt {

    private Thread thread;

    private volatile boolean started = false;

    public synchronized void start() {
        if (started) {
            return;
        }
        started = true;
        thread = new Thread(() -> {
            while (true) {
                Thread currentThread = Thread.currentThread();
                boolean interrupted = currentThread.isInterrupted();
                if (interrupted) {
                    log.info("料理后事,停止线程");
                    break;
                }
                try {
                    Thread.sleep(2000);
                    log.info("执行监控记录");
                } catch (InterruptedException e) {
                    currentThread.interrupt();
                    e.printStackTrace();
                }
            }
          
        }, "监控线程");
        thread.start();
    }

    public synchronized  void stop() {
        log.info("打断");
        started = false;
        thread.interrupt();
    }

    public static void main(String[] agrs) throws InterruptedException {
        TPTInterrupt t = new TPTInterrupt();
        t.start();
        t.start();
        Thread.sleep(3500);
        t.stop();

    }
}

守护线程

import lombok.extern.slf4j.Slf4j;

/**
 * @Author blackcat
 * @create 2021/7/20 14:20
 * @version: 1.0
 * @description:
 *
 * 守护线程,只要其它非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束。
 */
@Slf4j
public class ThreadDaemon {

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    break;
                }
            }
            log.info("t1结束");
        }, "t1");
        //启动当主线程结束 当前线程也会强制结束
        //       t1.setDaemon(true);
        t1.start();

        Thread.sleep(1000);
        log.info("main 结束");
    }
}

线程状态

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

image-20210720173029176.png

/**
 * @Author blackcat
 * @version: 1.0
 * @description:线程的六种状态
 */
@Slf4j
public class ThreadState {

    public static void main(String[] args) throws IOException {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                log.info("running...");
            }
        };

        Thread t2 = new Thread("t2") {
            @Override
            public void run() {
                while(true) { // runnable

                }
            }
        };
        t2.start();

        Thread t3 = new Thread("t3") {
            @Override
            public void run() {
                log.info("running...");
            }
        };
        t3.start();

        Thread t4 = new Thread("t4") {
            @Override
            public void run() {
                synchronized (ThreadState.class) {
                    try {
                        Thread.sleep(1000000); // timed_waiting
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t4.start();


        Thread t5 = new Thread("t5") {
            @Override
            public void run() {
                try {
                    t2.join(); // waiting
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        t5.start();

        Thread t6 = new Thread("t6") {
            @Override
            public void run() {
                synchronized (ThreadState.class) { // blocked
                    try {
                        Thread.sleep(1000000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t6.start();

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //NEW
        log.info("t1 state {}", t1.getState());
        //RUNNABLE
        log.info("t2 state {}", t2.getState());
        //TERMINATED
        log.info("t3 state {}", t3.getState());
        //TIMED_WAITING/BLOCKED
        log.info("t4 state {}", t4.getState());
        //WAITING
        log.info("t5 state {}", t5.getState());
        //BLOCKED/TIMED_WAITING
        log.info("t6 state {}", t6.getState());
    }
}