zoukankan      html  css  js  c++  java
  • 多线程 001

    其实java虚拟机jvm不止一个线程,想想执行java程序的是主线程,但垃圾回收机制肯定有一个子线程负责垃圾回收
     
    如何自定义一个线程呢?
    1.创建一个类继承Thread
    2.重写Thread的run方法
            目的:将自定义的代码存储在run方法中,让线程运行
    3.实例化一个线程,调用start方法
        start方法的作用:启动线程;调用run方法
    直接调用t.run方法不行吗,结果是执行完run方法才执行main的,不会出现上面交替的情况
    start和run的区别:start运行(启动)了线程,并执行run方法;而调用run方法,仅仅执行run里的代码
    Demo d1 = new Demo();---->创建一个线程
    d1.start();---->启动线程
    -------------------------------------------------------------------
    体会一下。。。。。
    电脑CPU在快速切换多个进程,而每个进程里面又在不停地切换多个线程。
    run方法用于存储线程运行的代码
    ------------------------------------------------------------------------------
    Thread的五种状态
    也可以具体到6种状态,将冻结状态分为:睡眠状态、等待状态
    当多个线程运行,同一时间只有一个线程能抢到cpu,此时,其它线程就暂时处于阻塞状态;
    调用sleep(时间)方法,可以让一个线程进入冻结状态,当冻结时间结束时,他会进入阻塞状态,抢cpu;
    当调用wait方法时,线程进入冻结状态(等待),调用notify方法,线程重新启动;
    当一个线程被stop(),线程就消亡了,或者程序结束运行,也消亡;
    ---------------------------------------------------------------------------------------
    获取线程对象和名称
     static Thread currentThread(): 获取当前线程的对象(由于是Thread类中的静态方法,所以可以不用实例化直接调用)
    getName():获取线程的名称
    设置线程名称setName()或者构造函数
    -----------------------------------------------------------------------------
    获取线程名称currentThread()
    Thread.currentThread().getName();
    --------------------------------------------------------------------------------
    ------------------------------------------------------------
    设置线程名称
    super(name)-->重写父类的方法,父类有一个改名的构造方法
     
    Test t = new Test("线程名称");
    -------------------------------------------------------------------------
    卖票的小程序
    我一共100张票,3个窗口去卖票,结果卖了300张!每张票都被卖了3次。。。- -!
    解决办法:将票定义为静态的private int ticket = 100;
    但是静态方法生命周期太长了,于是,引出线程的第二种创建方式
    ----------------------------------------------------------------------
    线程的第二种创建方式:实现Runnable接口
    创建一个类实现Runnable接口,然后实现run方法
     
    这次,有四个窗口,只卖了100张票,不会出现重复卖票的情况了
    首先要说明,Runnable不是一个线程,开的四个线程是通过main函数中的实例化t1 2 3 4实现的
    然后,看Ticket类中,输出语句Thread.currentThread().getName()方法,咦,刚开始不是可以省略Thread吗,这次怎么不能了?因为上次类继承了Thread类,所以可以直接调用
    而这次Runnable不是线程,但是currentThread方法是静态的,所以可以通过类名调用
    ----------------------------------------------------------------------
    第二种实现步骤:
    1.定义类实现Runnable接口
    2.覆盖Runnable接口中的run方法
    3.创建Thread对象
    4.强Runnable接口的子类对象作为参数传到Thread类的构造函数中
    5.调用Thread的start方法开启线程,运行Runnable接口子类的run方法
    -----------------------------------------------------------------------
    继承Thread方法和实现Runnable接口的区别
     
    先说说Runnable是怎么来的
    看,第一个student继承Thread,重写了run方法
    但是,第二个学生继承了Person类,java只支持单继承,那么我就没有办法在继承Thread类了,
    那怎么办呢,java工程师就引入Runnable接口,解决这个问题
    我继承了Person类的同时,可以实现Runnable接口,然后实现接口的run方法
    然后,我把这个实现Runnable的子类对象传给Thread(Runnable target)
    调用start方法就可以了
    -----------------------------------------------------------------------------------------------
    多线程的安全问题
    还是那个买票的例子
    想象一下这样的情景:只剩下最后一张票了,当我窗口1判断了if(tick>0),窗口1休眠10毫秒;此时,窗口2开始判断if(tick>0),也休眠10毫秒;窗口3、窗口4都是这样,那么,这四个都符合条件了,等休眠结束后,窗口1取出1号票,此时已经没票了;但是...由于之前窗口2、3、4都符合if语句,那么,他们也会继续执行,结果,就会取出0号票、-1、-2号票,这不就出问题了吗 - -!
     
     
     
    错误的原因:
    当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程就参与进来,导致共享数据出现错误。
    ------------------------------------------------------------
    解决办法:
    对多条操作共享数据的语句,只能让一个线程都执行完。执行过程中,其他线程不可以参与进来。
     
    java的解决方式:同步代码块
    synchronized(对象){
    需要被同步的代码
    }
    由于同步代码块需要一个实例对象作为参数,所以我用obj作为参数
    看下结果
    这个同步代码块是怎么玩的呢:
    其实静态代码块就相当于一个开关,默认是开着的,当0线程进去后,它会立马关闭,然后才执行里面的代码;
    执行完毕后,同步代码块才重新打开。
    结合上面代码,里面有个休眠10毫秒,0线程就处于休眠状态;此时,1、2、3线程就开始执行,但执行到同步代码块时,发现它是关闭的,只好阻塞在那里,等0休眠结束后,执行卖票,然后跳出代码块。1、2、3线程就可以进去了,但是此时,进去后判断ticket已经==0了,不成立了,就卖不出-1号票了。
     
    举个生活实例:火车上的厕所,无人才能进去,进去就上锁,此时第二个人不能进去
    ----------------------------------------------------------------------------------------------
    同步的前提:
    1.必须两个或者两个以上的线程
    2.必须是多个线程使用同一个锁
    3.必须保证同步中只能有一个线程在执行
     
    好处:解决了多线程的安全问题
    弊端:多个线程都判断这个锁,较为消耗资源
     
    如何找问题:
    1.明确那些代码是多线程运行的代码
    2.明确共享数据
    3.明确多线程运行中哪些语句是操作共享数据的
    ---------------------------------------------------------------
    同步函数
    think:函数也具备封装代码的功能,同步代码块也是封装代码,多出来一条就是同步性,那么,能不能搞个同步函数呢
    synchronized用来修饰函数就行了
    public synchronized void add(int n){
    }
    那么,就可以把同步代码块中的数据封装成同步函数了
    那么,同步函数到底是谁的锁呢,答案是this的
    我定义一个boolean型deal,注意,同步代码块中的synchronized参数是this,而交替执行同步方法和同步代码块,并没有出现安全问题,也就是说,这两个操作的是同一个锁,即,同步函数的是this的锁。
     
    --------------------------------------------------------------
    如果同步函数被静态修饰,使用的锁不再是this的了,
    因为,静态函数在方法区,不可能定义this,
    静态进内存的时候内存中没有本类对象对象,但是有该类的字节码文件.class
    所以,静态同步函数的对象时字节码文件对象---->类名.class
    ------------------------------------------------------------------
    同步的问题
    死锁
    同步代码块中调用同步函数,而同步函数中也调用同步代码块,就可能产生死锁
     
     
     
  • 相关阅读:
    prototype.js超强的javascript类库
    MySQL Server Architecture
    Know more about RBA redo block address
    MySQL无处不在
    利用Oracle Enterprise Manager Cloud Control 12c创建DataGuard Standby
    LAMP Stack
    9i中DG remote archive可能导致Primary Database挂起
    Oracle数据库升级与补丁
    Oracle为何会发生归档日志archivelog大小远小于联机重做日志online redo log size的情况?
    Oracle Ksplice如何工作?How does Ksplice work?
  • 原文地址:https://www.cnblogs.com/aisi-liu/p/4227628.html
Copyright © 2011-2022 走看看