zoukankan      html  css  js  c++  java
  • java多线程编程(二创建线程)

    1、概念     

         因为java是完全面向对象的,所以在java中,我们说的线程,就是Thread类的一个实例对象。所以,一个线程就是一个对象,它有自己字段和方法。

    2、创建线程

         创建线程有2种方法:1、扩展线程父类Thread类 , 2、实现Runnable接口。2种方法是由区别的。

          提示:Thread类已经实现了Runnable接口,Thread类中不但实现了run方法,也定义了更多的,全面的线程对象的操作方法,而Runnable接口中只有run这一个方法。

           

    通过扩展Thread类

    public class Test  {
    
        public static void main(String[] args) 
        {
            
            System.out.println("我是"+Thread.currentThread().getName()+"线程");
            
            MyThread t1 = new MyThread("线程1");
            MyThread t2 = new MyThread("线程2");
            
            t1.start();      
            t2.start();
            
            System.out.println(Thread.currentThread().getName()+"线程运行完毕");
            
    
            
        }
    
        
    }
    
    
    class MyThread extends Thread
    {
    
        public MyThread()
        {
            super();
        }
        public MyThread(String name)
        {
            super(name);
        }
        
        
        @Override      //重写父类的run方法
        public void run() 
        {
    
           for(int i=0;i<5;++i)
           {       
               System.out.println("我是 "+this.getName());
            
               try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
           }
        }
        
        
    }

    输出:

    我是main线程
    main线程运行完毕
    我是 线程2
    我是 线程1
    我是 线程1
    我是 线程2
    我是 线程1
    我是 线程2
    我是 线程1
    我是 线程2
    我是 线程2
    我是 线程1

    总结法发现:3个线程抢占CPU资源 ,快速交替执行,谁也不等谁,他们只等CPU。

     通过实现Runnable接口

    public class Test  {
    
        public static void main(String[] args) 
        {
            
            MyThreadTest com = new MyThreadTest();
            
            Thread t1 = new Thread(com,"线程1");
            Thread t2 = new Thread(com,"线程2");
            
            t1.start();
            t2.start();
    
            
        }
    
        
    }
    
    
    class MyThreadTest implements Runnable
    {
    
    
        private int num = 50;
        @Override
        public  void run() 
        {
    
           while(num>=1)
           {
               System.out.println("来自"+Thread.currentThread().getName()+" num = "+ num);
               num--;
           }
        
            
        }
        
    }

    输出:(不同的机器和运行时间会输出不同的结果)

    来自线程2 num = 10
    来自线程1 num = 10
    来自线程2 num = 9
    来自线程1 num = 8
    来自线程2 num = 7
    来自线程1 num = 6
    来自线程2 num = 5
    来自线程1 num = 4
    来自线程1 num = 2
    来自线程1 num = 1
    来自线程2 num = 3

          我们发现线程1和线程2输出的数都不是完整的从10 ~1,因为他们2个程序共同操作一个“伪线程类“MyThreadTest 的实例,就是com。所以,当线程t1把num的值改为9的时候,这个时候t2访问到的num的值就是9了。这里涉及到线程同步的问题,我还在以后的随笔中讲解。

          我为什么叫MyThreadTest叫“伪线程类”?因为MyThreadTest类根本就不是一个线程类。它和Thread虽然都实现了Runnable接口,但是MyThreadTest和Thread没有继承关系,我们前面说过,java中的线程是Thread类的一个实例。好比Rectangle类和Triangle类都实现了Shape接口,难道一个三角形可以看成一个矩形吗?显然是不可以的。

          所以,我们通过Runnable接口去创建线程,还是需要借助Thread类。

          Thread t1 = new Thread(com);

          Thread t2 = new Thread(com);

          因为t1和t2在构造时,使用的同一个“伪线程类”对象com ,所以t1 t2操作的就是同一个对象com 。如果你不想这样,那就分别为t1 t2提供不同的"伪线程类"对象

      Thread t1 = new Thread(new MyThreadTest());

          Thread t2 = new Thread(new MyThreadTest());

    小结

           一、一般我们建议实现Runnable,虽然多写一行代码,但这样更灵活,可扩展性强。

          二、自定义线程中的run方法相当于主线程中的main方法,为什么要取名为main呢?因为这是java与系统之间的约定,main是程序入口的签名,他是一个标志,当java程序启动时,就会去调用名字为main 的方法。同理,一个新线程要执行它的业务逻辑代码,也需要一个约定好的名字:run。它和其他方法没有任何区别,只不过名字特殊而已。

    3、Thread类中一些常用的线程操作方法(标有*的是要重点掌握的方法)

    *t.start() 使t线程进入准备状态,能有被CPU执行的权利,但不一定马上被执行
    *t.run() 不要自己显示调用run方法,当CPU给某个线程执行机会时,run方法就会自动执行。
    t.getName() 返回此线程的名字
    t.setName(String  name) 设定线程的名字
    t.setPriority(int level)   

    设定线程的优先级

    Thread.MAX_PRIORITY  最高优先级,10

    Thread.MIN_PRIORITY   最低优先级   1

    Thread.NORM_PRIORITY 一般优先级 5

    设置优先级后,JVM的事件调度器会根据线程的优先级来按顺序来调用线程。

    通常高优先级线程会先于低优先级运行,但是这个规律不是总成立的。

    优先级只会改变线程谁最先启动,和谁最后启动。CPU对每一个线程的单次执行时间片是固定的。

    t.getPriority() 获取线程的优先级
    *t.join()  线程合并。这句话写在哪个线程里面,就是让t1线程加入到那个线程的执行流程中。暂停执行这句话的线程,直到t1线程执行完毕后,在接着执行   。例如在main线程中有t1.join()     ,执行到这个join函数时,main线程则暂,直到t1线程执行完毕, 在回来main接着执行。
    *t.isAlive() 线程是否活着
       
       
       
    静态方法:  
    Thread.yield() 该线程主动放弃被CPU执行的机会,让出CPU给相同优先级的线程,自己再次进入准备状态  ,下次会接着执行。这个方法的效果一般不会太明显,因为线程放弃CPU后再次进入准备阶段,而后又获得CPU的过程会很快。
    Thread.currentThread() 反回当前正在运行的线程的引用
    *Thread.sleep(long millis) 让线程睡眠millis毫秒,挂起,进入阻塞状态。此时CPU就会释放对此线程,而去 执行其它的线程睡眠时间过去后,该线程再次进入准备状态,等待被CPU执行。所以millis的值是至少的暂停时间。而不是绝对的暂停时间。
    未完。。。待补充  
  • 相关阅读:
    JAVA内部类详解
    表、栈和队列
    大型网站架构演化<二>
    eclipse中build path 中JDK与java compiler compliance level的问题(转)
    XFire构建服务端Service的两种方式
    SpringMVC简单例子
    Mybatis
    java静态代码块 类加载顺序问题。
    Tomcat6.0数据源配置
    解析xml的几种方式
  • 原文地址:https://www.cnblogs.com/lulipro/p/5351231.html
Copyright © 2011-2022 走看看