zoukankan      html  css  js  c++  java
  • 多线程(Thread,Runnable)

    一、多线程。

        1、进程:一个正在执行的程序叫做进程。
              每一个进程的执行都有一个执行顺序,这个顺序就是一个执行的路径,或者叫做一个控制单元。

        2、线程:就是上述进程中的一个独立控制单元, 线程在控制着进程的执行。
              一个进程至少有一个线程。

          Java virtual machine 启动时会有一个进程 Java.exe, 该进程中至少有一个进程负责Java程序的执行,
          而此进程运行的代码存在于 main方法中。
          而该线程称之为主线程。

        扩展:在更细节的说明jvm, jvm启动的时候不止主函数一个线程在进行, 还有Java垃圾回收机制的线程。

    二、如何在自定义的代码中, 定义一个多线程呢?

        Java中对于线程这类事物进行了描述, 并封装成 Thread类,

      要创建一个线程有两种方法:

        创建线程的第一种方法: 就是继承至 Thread 类
                      步骤:1、定义一个类,继承Thread类。
                         2、复写类中的run方法。
                                  为了定义线程要执行的代码。
                         3、new一个新的对象,创建线程。
                           4、调用其start方法,
                                  该方法有两个作用:1)、启动线程 2)、调用run 方法。

                      此时main函数中的程序和 run中的程序同时进行。

              实操结果:发现每次执行的结果都不一样, 这是因为多个线程在获取cup的资源, CPU执行到那个线程,哪个线程就开始运行。
                    而且每一时刻CPU中都只在运行一个进程(线程),CPU在做高速切换。 此切换具有

                    所以:随机性是多线程的一个特点。


              在子程序中重写run方法的原因: 因为Thread类是为了描述一个线程, 所以该类就有一个功能: 即存储要执行的代码。
              该功能就是就是run()方法。 就是说:run()方法中的代码就是线程执行的代码(类似于main)。

              注意:只有在多线程开启语句执行了过后才会有多线程执行(start语句之后才开启多线程)。



        创建线程的第二种方法: 就是声明实现一个Runnable接口。

                      步骤:1、定义一个类,其实现了Runnable接口,
                                      class Test implements Runnable
                         2、复写该类中实现Runable而来的run方法。
                                      确定线程中应执行代码:public void run(){}
                           3、new一个该类的新对象 t。
                                      Test t = new Test();
                           4、new一个Thread 方法,并将 对象 t 当做构造实参传进去(即指定线程要执行的run方法)。
                                      Thread th = new Thread(t);
                           5、调用该Thread 对象的start方法,
                                      th.start();

              继承方式和实现方式的区别:

                 实现方式: 避免了单继承带来的局限性, 在定义多线程的时候, 建议使用实现方式。
                       其线程代码存放在接口子类对象的run方法中。(只要传入Thread的对象相同,可以实现多线程共同执行同一份代码)

                 继承方式:其线程代码存放在Thread子类的对象run方法中, 一个线程只能执行自己的run中的代码。



    三、线程中的方法

          1、Thread 中,定义了一个name私有的String类型的变量,在new Thread对象的时候可以传入字符串名称,

                      (注:在创建子类对象的时候要复写构造函数 super())
                使用getName()方法可以拿到这个变量。

                其实线程有默认的名称: 就是Thread-编号, 该编号从 0 开始。

            static Thread currentThread():获取当前线程的对象。
            getName():获取线程的名称。 而设置线程 的名称: setName(), 或者构造函数。




    四、多线程中的安全问题

        问题原因:是因为多个线程在操作同一个共享数据时(实现方法操作同一个对象, 或继承方法操作一个静态数据),其中某条线程只执行了一部分,没有执行完,
              另一个线程就进来参与执行,就发生共享数据错误。

        解决方法:在多个线程操作同一个共享数据时,同时只让一个线程对数据进行操作,该过程中,其它线程不能参与执行。

        Java对线程的安全问题提供了专业的解决工具:

            1、同步代码块:
                    synchronized(对象)
                    {
                        需要被同步的代码(这里就是数据代码);
                    }
              这里的 对象 是任意对象,如同一个 锁,只有持有锁的线程才能同步执行数据代码;
             没有锁的进程,即使拿到了cpu 的执行权,也不能执行数据代码。(例子:火车上的卫生间--老毕例子)


              好处:必须保证同步中只能有一个线程在运行。
              弊端:降低了程序效率。

            2、非静态同步函数:

                就是将synchronized关键字放在函数的修饰符位置。

                for example: synchronized void run(){} (注:一般不能同步run方法,此处只为举例。)

              同步函数的“锁”(对象)是调用这个方法时的对象, 即:相当于 this

            3、静态同步函数:
                如果上述同步函数是被静态(static)修饰的,
                其静态“锁” 就是调用这个方法的类的字节码对象, 即: 类名.class【类型为Class】


              (因为该静态方法进内存时,没有该类的对象,但是却有该类的 字节码对象,使用该字节码对象为同步锁)


            同步的前提:1、有两个以上的线程在执行同一份代码,
                  2、它们使用了同一把锁。



    五、死锁

        出现原因: 同步 中 嵌套 同步,且同步的锁不一样。(避免此情况出现)。

  • 相关阅读:
    [AGC005D] ~K Perm Counting
    [国家集训队]middle
    CF842D Vitya and Strange Lesson
    浅谈脚本化css(三)之方块运动函数
    浅谈脚本化css(二)
    浅谈脚本化css(一)
    滚动条详解及制作(三)
    滚动条详解及制作(二)
    滚动条详解及制作(一)
    javascript定时器详解
  • 原文地址:https://www.cnblogs.com/soficircle/p/6642509.html
Copyright © 2011-2022 走看看