美文网首页
多线程基础、一

多线程基础、一

作者: 在前行路上的奔跑 | 来源:发表于2020-03-05 19:18 被阅读0次

    一、 基础概念

    1、什么是进程

    进程是系统资源分配的独立实体、每个进程都拥有独立的地址空间。

    2、什么是线程

    线程是CPU调度的最小单位,必须依赖进程而存在,每个线程还拥有自己的寄存器和栈

    3.、Cpu时间片轮转机制

    cpu轮转分配时间片给线程队列,调度过程需要上下文切换

    4、并发编程的利弊

    好处:充分利用cpu资源,加快用户响应的时间,程序模块化,异步化

    弊端:可能发生线程安全问题、死锁、线程太多拖垮cpu

    二、什么是线程安全?

    在多线程环境中,能够保证程序的正确性,和我们预期是一样的,它就是线程安全的

    • 原子性:提供了互斥访问,同一时刻只能有一个线程对它进行操作

    • 可见性:一个线程对主内存的修改可以及时的被其他线程观察到

    • 有序性:在并发时,程序的执行可能会出现乱序。给人的直观感觉就是:写在前面的代码,会在后面执行。有序性问题的原因是因为程序在执行时,可能会进行指令重排,重排后的指令与原指令的顺序未必一致。

    三、 如何在Java中实现线程

    主要有以下7种创建方式

    1. 继承Thread类
    
    public class Demo1 extends Thread {
    
    
    
        @Override
    
        public void run() {
    
            System.out.println(this.getName());
    
        }
    
    
    
        public static void main(String[] args) {
    
            new Demo1().start();
    
        }
    
    
    
    }
    
    
    1. 实现Runnable接口
    
    public class Demo2 implements Runnable {
    
    
    
        @Override
    
        public void run() {
    
            System.out.println(Thread.currentThread().getName());
    
        }
    
    
    
        public static void main(String[] args) {
    
            Demo2 demo2 = new Demo2();
    
            new Thread(demo2, "t1").start();
    
        }
    
    }
    
    
    1. 实现Callable接口
    
    /**
    
      * 异步获取结果
    
      */
    
    public class Demo3 implements Callable<String> {
    
    
    
        public static void main(String[] args) {
    
            Demo3 demo3 = new Demo3();
    
            FutureTask<String> futureTask = new FutureTask(demo3);
    
            new Thread(futureTask).start();
    
    
    
            try {
    
                String result = futureTask.get();
    
                System.out.println("result is " + result);
    
            } catch (Exception e) {
    
                e.printStackTrace();
    
            }
    
        }
    
    
    
        @Override
    
        public String call() throws Exception {
    
            System.out.println(Thread.currentThread().getName() + " is running");
    
            return "结果";
    
        }
    
    
    
    }
    
    
    1. 匿名内部类方式启动

    2. Lambda方式启动

    3. TimeTask方式启动

    TimeTask实现了Runnable接口,Timer内部有个TimerThread继承自Thread,故实际还是Thread + Runnable

    
    public static void main(String[] args) {
    
            Timer timer = new Timer();
    
            timer.scheduleAtFixedRate((new TimerTask() {
    
                @Override
    
                public void run() {
    
                    System.out.println(LocalDate.now());
    
                }
    
            }), 5000, 3000);
    
        }
    
    
    1. 线程池启动多线程
    
    /**
    
      * 线程池
    
      */
    
    public class Demo4 implements Runnable {
    
        /**
    
          * ExecutorService的4种方式:
    
          * 1.ExecutorService newFixedThreadPool(5);
    
          * 2.ExecutorService newCachedThreadPool();
    
          * 3.ExecutorService newSingleThreadExecutor();
    
          * 4.ScheduleExecutorService newScheduledThreadPool();
    
          */
    
        @Override
    
        public void run() {
    
            System.out.println("Thread Pool");
    
        }
    
    
    
        public static void main(String[] args) {
    
            ExecutorService executorService = Executors.newCachedThreadPool();
    
            executorService.submit(new Demo4());
    
        }
    
    }
    
    
    
    

    思考:用Runnable还是Thread

    Java是不支持类的多重继承的,但是可以实现多个接口,所以如果需要继承其它类时,使用Runnable更好

    Java中的Runnable和Callable有什么不同

    Runnable和Callable都代表那些要在不同的线程中执行的任务、它们的主要区别是Callable的Call()方法可以返回值和抛出异常,而Runnable的Run()方法没有这些功能

    五、线程的生命周期

    生命周期图.png

    线程的生命周期的5种状态:新建、就绪、运行、阻塞、终止

    • 新建(New)

      线程对象创建后,便进入新建状态

    • 就绪(Runnable)

      调用线程对象的start()方法后,便处于就绪状态,此时线程等待Cpu调度执行

    • 运行(Running)

      当就绪的线程被调度并获取Cpu资源时,便进入运行状态,执行run()方法中的操作

    • 阻塞(Blocked)

      处于运行状态的线程,因为某些原因导致线程编程阻塞状态,比如执行sleep()、wait()、join()之后都会处于阻塞状态

      需要注意一点

      sleep()不会释放cpu资源,而wait将会释放cpu资源,让其它线程执行

    • 终止(Terminated)

    线程执行结束,或者出现异常情况导致线程提前终止,那么线程的生命周期都将结束

    为了方便大家理解阻塞状态,这里在上一个图,之所以没在画一起是因为放到一起会有一种很乱的感觉,不容易阅读

    生命周期图 (1).png

    下一篇:我们细说Synchonized和JMM volatile 缓存一致性

    相关文章

      网友评论

          本文标题:多线程基础、一

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