多线程概述和常见问题

来源:互联网 发布:多益网络上市失败 编辑:程序博客网 时间:2024/05/07 09:26

       谈到线程,不得不先要理解什么是进程。进程是一个正在执行中的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫做一个控制单元。线程(Thread)就是进程中的一个独立的控制单元,线程在控制着进程的执行。一个进程中至少有一个线程,即至少有一个控制单元。

            Java虚拟机启动时会有一个进程java.exe,该进程中至少一个线程负责java程序的执行, 而且该线程称之为主线程。需要强调的是JVM在启动时不止有一个进程,还有负责

  垃圾回收机制的线程。

           如何在自定义的代码中,自定义一个线程 呢?线程存在于某一个进程当中,进程是系统创建的,所以Java中已经提供了此类事物的体现,java.lang包中有一个Thread类。

创建线程的一种方式就是:

            1.  定义类继承Thread类

            2.  重写(覆盖)Thread中的run( )方法。目的是:将自定义的代码存储在run方法中,让线程运行

            3. 调用线程的start( )方法。 该方法有两个作用:启动线程,调用run()方法

                         
示例代码1:

package com.itheima.day11;

class Demoextends Thread{
         public void run(){
               for (int x = 0; x < 500; x++) {
                        System.out.println("demo run---"+x);
        }
        
    }
}

public class ThreadDemo {

       public static void main(String[] args) {

                 //继承完之后,创建对象,即创建好了一个线程

                  Demo d = new Demo();

                  //开启线程并执行该线程的run()方法,start是调用的底层,让控制台执行的动作

                  d.run();

                  for (intx = 0; x < 500; x++) {
                
                System.out.println("Hello World!--"+x);
            }
        }

  }

发现
        每一次的运行结果都不同,因为多个线程都在获取CPU的执行权,CPU执行到哪个进程的线程,就会执行哪一个进程
        明确一点:在某一时刻,只能有一个程序在运行(多核除外)

原理
         CPU在做着快速的切换,以达到看上去同时运行的效果
         这就是多线程的一个特性:随机性(哪个程序抢到CPU资源,它就会执行,执行多长时间,由CPU决定)

事实

             Windows本身是一个多任务操作系统,表面看似在同时执行多个程序,其实,CPU在某一个时间内只能执行一个程序,它是在多个程序之间进行快速的切换,速度非常之快,所以会认为是同时执行,其实是在切换每一个进程中的线程,若一个进程中有多个线程,CPU也在进行切换,这就是为什么同一时间内开的程序越多,电脑就会运行的
越慢(多个线程在抢夺CPU资源,但是是有CPU决定的),但是若为双核,多核,就能够实现同时执行,双核多核
以后内存就是 瓶颈,临时存储空间要足够大,双核标配内存要在2G以上

run( )start( )的特点

               Thread类用于描述线程,该类定义了一个功能,即run()方法,用于存储线程要运行的代码。

               主线程运行的代码,存储在main()方法中,这是由JVM定义的,这就是虚拟机调用main()方法的原因
       因为是主线程在调用.Java中规定了自定义的线程的代码,存储在Thread的run()方法中 start()调用的是 Thread类

      所属对象的run()方法,要沿袭父类功能,重写父类内容

调用start()run() 的不同 

          A.        d.start();--->开启线程并执行该线程的run()方法,start是调用的底层,让控制台执行的动作.打印结果是
             交替打印

          B.       d.run();---->仅仅是对象调用方法,而线程创建了,并没有执行.(仅仅是封装了线程要运行的代码).打印结果是
              先将run中封装的代码执行完之后再执行start的代码,没有启动主线程
             
创建线程的第二种方式:实现Runnable接口
 
  步骤
  1. 定义类实现Runnable
  2. 覆盖Runnable接口中的run()方法
      
  3. 通过 Thread类创建线程对象


  4. 将Runnable接口的子类对象传递给Thread类的构造函数
               为什么要将Runnable接口的子类对象传递给Thread的构造函数呢?
       因为,自定义的run()方法所属的对象是Runnable接口的子类对象
       所以要让线程指定对象的run()方法,就必须明确该run方法所属对象


  5. 调用Thread类的start()方法,开启线程并调用Runnable接口子类的run()方法
 

 实现方式和继承方式有什么不同呢?
 
 实现方式好处:避免了单继承的局限性
 在定义线程时,建议使用实现方式
 存放线程代码位置不同:
 继承Thread:线程代码存放在Thread子类的run()方法中
 实现Runnable,线程代码存放在接口的子类run()方法中
 
 注意
 Thread类本身也实现Runnable接口,Runnable的定义其实就是在确线程运行代码所存放的位置
 

示例代码2:

package com.itheima.day11;

class Ticket1 implements Runnable{
      private int tick = 100;   

      public void run(){  
           while(true){
                 if(tick>0){
                       System.out.println(Thread.currentThread().getName()+" sale:"+tick--);
            }
            
        }
    }
}

public class ThreadRunnableDemo {

    public static void main(String[] args) {
        Ticket1 t = new Ticket1();

         //创建了一个线程

         Thread t1 = new Thread(t);
         Thread t2 = newThread(t);
         Thread t3 = new Thread(t);
         Thread t4 = new Thread(t);

         /**
         * 分析:
         *作用是开启线程,调用的是Thread类中的run()方法,但是此时的Ticket3实现的是
         *Runnable接口,其中也有run方法,此时Thread中的run()中没有卖票的代码                   
         */       

           t1.start();
           t2.start();
           t3.start();
           t4.start();
      }

}


0 0
原创粉丝点击