美文网首页
Java并发之线程状态及创建(1)

Java并发之线程状态及创建(1)

作者: 小马蛋 | 来源:发表于2019-11-20 09:15 被阅读0次

    一、状态解读

    Java线程状态迁移.png

    1、New 初始状态

    创建线程后,未运行

    2、Runnable 可运行状态

    可能在运行也可能在等待CPU时间片
    同时也包含了操作系统线程的Ready 和 Running

    着重说一下Thread.yield()
    Thread.yield()方法作用是:暂停当前正在执行的线程对象(及放弃当前拥有的cup资源),并执行其他线程。

    yield()做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的
    目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被
    线程调度程序再次选中。

    结论:yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。

    3、Blocked 阻塞

    等待获取一个Synchronized锁,如果抢占到锁就会离开此状态。

    4、Waiting 等待

    等待其它线程显示的唤醒,否则一直等待下去。

    进入 退出
    没有设置Time out参数的Object.wait() Object.notify() 或 Object.notifyAll()
    没有设置Time out参数的Thread.join() 被调用的线程执行完毕
    LockSupport.park() LockSupport.unpark(Thread thread)

    5、Timed Waiting 超时等待

    进入 退出
    Object.wait(Long) Object.notify() 或 Object.notifyAll()
    Thread.join(Long) 超时退出 或 被调用的线程执行完毕
    Thread.sleep(Long) 超时退出
    LockSupport.parkNanos(Long) LockSupport.unpark()
    LockSupport.parkUntil(Long) LockSupport.unpark()

    6、Terminated 终止状态

    当线程的run()方法执行完毕或者主线程的main()方法完毕,就终止了,也许在这一刻,该线程还是存活的,但是它就要被终止了。

    在一个终止的线程上调用start()方法会抛出异常java.lang.IllegalThreadStateException,线程一旦被终止,就无法再次运行。

    二、创建

    Java线程的创建分为四种方式:

    1)继承Tread类

        public class MyThread extends Thread {
            public void run() {
                System.out.println("我是继承于Thread的线程类");
            }
        }
        
        ==================分割线====================
    
        @Slf4j
        public class JunitTest {
            @Test
            public void test() throws InterruptedException {
                MyThread thread = new MyThread();
    
                thread.start();
        
                Thread.sleep(3000);
            }
        }
    

    继承Thread类,重写其run()方法,然后通过start()方法调用即可,如果直接调用run()方法,那么就相当于调用同步方法,只有调用start()才是启动线程的正解。

    2)实现Runnable接口

        public class MyThread implements Runnable {
            @Override
            public void run() {
                System.out.println("我是实现Runnable接口的线程类");
            }
        }
    
        ==================分割线====================
    
        @Slf4j
        public class JunitTest {
            @Test
            public void test() throws InterruptedException {
                MyThread myThread = new MyThread();
                
                // 传入MyThread实例
                Thread thread = new Thread(myThread);
        
                thread.start();
                
                Thread.sleep(3000);
            }
        }
    

    实现Runnable接口,重写其run()方法。
    限于第一种方式,受继承的限制,第二种比第一种方式能好一些

    3)实现Callable接口

        public class MyThread implements Callable<String> {
        
            @Override
            public String call() throws Exception {
                System.out.println("我是实现Callable接口的线程类");
                return "ok";
            }
        }
    
        ==================分割线====================
    
        @Test
        public void test() throws Exception {
            Callable<String> callable = new MyThread();
        
            FutureTask<String> futureTask = new FutureTask<>(callable);
        
            Thread thread = new Thread(futureTask);
        
            thread.start();
        
            Thread.sleep(3000);
        }
    

    覆写call()方法,且支持返回值!

    4)通过线程池

    可以通过Executors来创建几种不同类型的线程池。Executors是一个线程池工厂,提供了创建线程池的很多方法。

    1)SingleThreadPoolExecutor

    只有一个线程的线程池。多个任务被提交到该线程池,先被缓存到队列(队列长度为Integer.MAX_VALUE),按照FIFO先进先出的原则进行任务处理。

    2)FixedThreadPool

    固定大小的线程池,内部存储的线程数量是固定的,和上面的处理流程极为类似,但是该线程池可以处理多个任务,多个任务被提交到线程池,按照以下过程进行处理:

    1)如果线程的数量未达到设置的数量,线程池会创建线程来处理任务。

    2)如果线程池里的线程数量达到了设置的数量,则取出空闲的线程执行任务

    3)如果没有空闲线程,则将任务缓存到队列(队列长度为Integer.MAX_VALUE),当有空闲线程时,按照FIFO的原则进行任务处理

    严格按照 1 -> 2 -> 3的过程进行处理。

    3)CachedThreadPool

    创建带缓存的线程池,这种线程池可以回收空闲线程,当任务到达后,直接使用空闲线程,没有空闲线程时,新建线程。线程池核心长度为0,最大长度为Integer.MAX_VALUE
    用户可以传入线程池的核心线程数(最小线程数),最大线程数量,保持时间,时间单位,阻塞队列这些参数,最大线程数设置为jvm可用的cpu数为宜。

    4)ScheduledThreadPool

    一个可定期或者延时执行任务的线程池

    5) WorkStealingPool

    创建拥有足够线程数的线程池来维持相应的并行级别,通过使用队列来减少竞争,默认为CPU的数量。它会通过工作窃取的方式,使得多核CPU不会闲置,总会有活着的线程让CPU去运行。

    所谓工作窃取,指的是闲置的线程去处理本不属于它的任务。

    在实际项目里,我们很少成规模的手动创建线程,一般都是使用线程池(池技术)将线程的创建、销毁、保留及其它管理工作交给线程池,用户无需知道其内部细节,即可使用。

    相关文章

      网友评论

          本文标题:Java并发之线程状态及创建(1)

          本文链接:https://www.haomeiwen.com/subject/kgmwictx.html