zoukankan      html  css  js  c++  java
  • 分析线程及多线程的使用

    实现方式:线程的实现方式有两种。一种是通过继承Thread类,并重写run()方法实现;另一种是通过实现Runnable接口并实现其run()方法。

    1、通过继承Thread类

    复制代码
     1 package thread;
     2 /**
     3  * 
     4  * @author CIACs
     5  *线程的生成通过继承Thread类实现
     6  */
     7 public class ThreadTest {
     8     public static void main(String[] args) {
     9         MyThread1 t1 = new MyThread1();
    10         t1.start();
    11         MyThread2 t2 = new MyThread2();
    12         t2.start();
    13     }
    14 
    15 }
    16 
    17 class MyThread1  extends Thread
    18 {
    19     
    20     @Override
    21     public void run() {
    22         for(int i=0;i<50;i++)
    23         {
    24             System.out.println("MyThread1 running: "+i);
    25         }
    26     }
    27 }
    28 class MyThread2 extends Thread
    29 {
    30     @Override
    31     public void run() {
    32         for(int i=0;i<50;i++)
    33         {
    34             System.out.println("MyThread2 running: "+i);
    35         }
    36     }
    37 }
    复制代码

    控制台输出结果:

    在这里我们可以看到两个线程会交叉执行,并不是一个先执行完后,另一个再执行。这就是说当线程启动后我们是不能控制执行顺序的。(当然是在还没用synchronized、wait()、notify()的时候)

    2、通过实现Runnable接口

    复制代码
     1 package thread;
     2 /**
     3  * 
     4  * @author CIACs
     5  *线程通过实现Runnable接口生成
     6  */
     7 public class ThreadTest2 {
     8     public static void main(String[] args) {
     9         Thread1 t1 = new Thread1();
    10         new Thread(t1).start();
    11         Thread2 t2 = new Thread2();
    12         new Thread(t2).start();
    13     }
    14 
    15 }
    16 
    17 class Thread1 implements Runnable
    18 {
    19     @Override
    20     public void run() {
    21         for(int i=0;i<50;i++)
    22         {
    23             System.out.println("Thread1 running "+i);
    24         }
    25         
    26     }
    27 }
    28 
    29 class Thread2 implements Runnable
    30 {
    31     @Override
    32     public void run() {
    33         for(int i=0;i<50;i++)
    34         {
    35             System.out.println("Thread2 running "+i);
    36         }
    37         
    38     }
    39 }
    复制代码

    控制台输出结果:

    1,线程名称

      1,在Thread类中可以通过getName()方法取得线程名称,通过setName()设置线程名称。

      2,线程的名称一般在启动线程前设置,但也允许为运行的线程设置名称,允许两个Thread对象有相同名称,但是应该避免。

      3,如果程序没有为线程指定名称,系统会自动为线程设置名称。

    复制代码
    class MyThread implements Runnable{    // 实现Runnable接口
        public void run(){    // 覆写run()方法
            for(int i=0;i<3;i++){
                System.out.println(Thread.currentThread().getName()
                        + "运行,i = " + i) ;    // 取得当前线程的名字
            }
        }
    };
    public class ThreadNameDemo{
        public static void main(String args[]){
            MyThread mt = new MyThread() ;    // 实例化Runnable子类对象
            new Thread(mt).start() ;        // 系统自动设置线程名称
            new Thread(mt,"线程-A").start() ;        // 手工设置线程名称
            new Thread(mt,"线程-B").start() ;        // 手工设置线程名称
            new Thread(mt).start() ;        // 系统自动设置线程名称
            new Thread(mt).start() ;        // 系统自动设置线程名称
        }
    };
    复制代码
    currentThread(),获取当前线程。

     运行结果:

    复制代码
    线程-A运行,i = 0
    线程-B运行,i = 0
    Thread-1运行,i = 0
    Thread-0运行,i = 0
    Thread-0运行,i = 1
    Thread-0运行,i = 2
    Thread-1运行,i = 1
    线程-B运行,i = 1
    Thread-2运行,i = 0
    线程-A运行,i = 1
    Thread-2运行,i = 1
    线程-B运行,i = 2
    Thread-1运行,i = 2
    Thread-2运行,i = 2
    线程-A运行,i = 2
    复制代码

      从效果看,指定的名称会自动出现,如果没有指定会发现线程使用自动编号完成,按照Thread-0,Thread-1.依次编号,实际上,肯定在类中存在static属性,用于记录编号

    2,当前线程:CurrentThread()

      程序可以通过currentThread()方法取得当前正在运行的线程对象,

    复制代码
    class MyThread implements Runnable{    // 实现Runnable接口
        public void run(){    // 覆写run()方法
            for(int i=0;i<3;i++){
                System.out.println(Thread.currentThread().getName()
                        + "运行,i = " + i) ;    // 取得当前线程的名字
            }
        }
    };
    public class CurrentThreadDemo{
        public static void main(String args[]){
            MyThread mt = new MyThread() ;    // 实例化Runnable子类对象
            new Thread(mt,"线程").start() ;        // 启动线程
            mt.run() ;    // 直接调用run()方法
        }
    };
    复制代码

      运行结果:

    main运行,i = 0
    线程运行,i = 0
    main运行,i = 1
    线程运行,i = 1
    main运行,i = 2
    线程运行,i = 2

      此时发现,程序中由主方法直接通过线程对象调用里面的run()方法,所有此时的结果包含一个"main",此线程就是由“mt.run()”产生的,因为调用此语句是由主方法完成的。

    也就是说,主方法本身也是一个线程---主线程

      问题:既然主方法都是以线程的形式出现,那么JAVA启动时候运行了多少线程?

      回答:至少启动了两个。

        从之前学习的情况来看,每当JAVA执行,都会启动一个JVM,每一个JVM都是在操作系统中启动一个线程。

        JAVA本身有垃圾回收机制,所以至少启动了两个线程:主线程,GC。

    3,判断线程是否在执行:isAlive

      

    复制代码
    class MyThread implements Runnable{    // 实现Runnable接口
        public void run(){    // 覆写run()方法
            for(int i=0;i<3;i++){
                System.out.println(Thread.currentThread().getName()
                        + "运行,i = " + i) ;    // 取得当前线程的名字
            }
        }
    };
    public class ThreadAliveDemo{
        public static void main(String args[]){
            MyThread mt = new MyThread() ;    // 实例化Runnable子类对象
            Thread t = new Thread(mt,"线程");        // 实例化Thread对象
            System.out.println("线程开始执行之前 --> " + t.isAlive()) ;     // 判断是否启动
            t.start() ;    // 启动线程
            System.out.println("线程开始执行之后 --> " + t.isAlive()) ;     // 判断是否启动
            for(int i=0;i<3;i++){
                System.out.println(" main运行 --> " + i) ;
            }
            // 以下的输出结果不确定
            System.out.println("代码执行之后 --> " + t.isAlive()) ;     // 判断是否启动
            
        }
    };
    复制代码

      运行结果:

    复制代码
    线程开始执行之前 --> false
    线程开始执行之后 --> true
     main运行 --> 0
     main运行 --> 1
     main运行 --> 2
    线程运行,i = 0
    代码执行之后 --> true
    线程运行,i = 1
    线程运行,i = 2
    复制代码

    4,线程强制运行:join()

      可以通过join()方法使得一个线程强制运行,线程强制运行期间,其他线程无法运行,必须等待此线程完成之后,才可以继续运行

    复制代码
    package Thread1;
    class MyThread implements Runnable{    // 实现Runnable接口
        public void run(){    // 覆写run()方法
            for(int i=0;i<50;i++){
                System.out.println(Thread.currentThread().getName()
                        + "运行,i = " + i) ;    // 取得当前线程的名字
            }
        }
    };
    public class demo1{
        public static void main(String args[]){
            MyThread mt = new MyThread() ;    // 实例化Runnable子类对象
            Thread t = new Thread(mt,"线程");        // 实例化Thread对象
            t.start() ;    // 启动线程
            for(int i=0;i<50;i++){
                if(i>10){
                    try{
                        t.join() ;    // 线程强制运行
                    }catch(InterruptedException e){}
                }
                System.out.println("Main线程运行 --> " + i) ;
            }
        }
    };
    复制代码

    运行结果:

    复制代码
    线程运行,i = 0
    Main线程运行 --> 0
    线程运行,i = 1
    Main线程运行 --> 1
    线程运行,i = 2
    Main线程运行 --> 2
    线程运行,i = 3
    线程运行,i = 4
    线程运行,i = 5
    线程运行,i = 6
    线程运行,i = 7
    线程运行,i = 8
    线程运行,i = 9
    Main线程运行 --> 3
    线程运行,i = 10
    Main线程运行 --> 4
    线程运行,i = 11
    线程运行,i = 12
    线程运行,i = 13
    Main线程运行 --> 5
    线程运行,i = 14
    Main线程运行 --> 6
    线程运行,i = 15
    线程运行,i = 16
    线程运行,i = 17
    线程运行,i = 18
    线程运行,i = 19
    Main线程运行 --> 7
    线程运行,i = 20
    Main线程运行 --> 8
    线程运行,i = 21
    Main线程运行 --> 9
    线程运行,i = 22
    Main线程运行 --> 10
    线程运行,i = 23
    线程运行,i = 24
    线程运行,i = 25
    线程运行,i = 26
    线程运行,i = 27
    线程运行,i = 28
    线程运行,i = 29
    线程运行,i = 30
    线程运行,i = 31
    线程运行,i = 32
    线程运行,i = 33
    线程运行,i = 34
    线程运行,i = 35
    线程运行,i = 36
    线程运行,i = 37
    线程运行,i = 38
    线程运行,i = 39
    线程运行,i = 40
    线程运行,i = 41
    线程运行,i = 42
    线程运行,i = 43
    线程运行,i = 44
    线程运行,i = 45
    线程运行,i = 46
    线程运行,i = 47
    线程运行,i = 48
    线程运行,i = 49
    Main线程运行 --> 11
    Main线程运行 --> 12
    Main线程运行 --> 13
    Main线程运行 --> 14
    Main线程运行 --> 15
    Main线程运行 --> 16
    Main线程运行 --> 17
    Main线程运行 --> 18
    Main线程运行 --> 19
    Main线程运行 --> 20
    Main线程运行 --> 21
    Main线程运行 --> 22
    Main线程运行 --> 23
    Main线程运行 --> 24
    Main线程运行 --> 25
    Main线程运行 --> 26
    Main线程运行 --> 27
    Main线程运行 --> 28
    Main线程运行 --> 29
    Main线程运行 --> 30
    Main线程运行 --> 31
    Main线程运行 --> 32
    Main线程运行 --> 33
    Main线程运行 --> 34
    Main线程运行 --> 35
    Main线程运行 --> 36
    Main线程运行 --> 37
    Main线程运行 --> 38
    Main线程运行 --> 39
    Main线程运行 --> 40
    Main线程运行 --> 41
    Main线程运行 --> 42
    Main线程运行 --> 43
    Main线程运行 --> 44
    Main线程运行 --> 45
    Main线程运行 --> 46
    Main线程运行 --> 47
    Main线程运行 --> 48
    Main线程运行 --> 49
    复制代码

    3.5  线程的休眠

       在线程中允许一个线程进行暂时的休眠,直接使用Thread.sleep()方法即可。

      sleep定义格式:

    public static void sleep(long milis,int nanos)
           throws InterruptedException

      首先,static,说明可以由Thread类名称调用,其次throws表示如果有异常要在调用此方法处处理异常

    所以sleep()方法要有InterruptedException 异常处理,而且sleep()调用方法通常为Thread.sleep(500) ;形式。

      例子:

    复制代码
    package Thread1;
    class MyThread implements Runnable{    // 实现Runnable接口
        public void run(){    // 覆写run()方法
            for(int i=0;i<50;i++){
                try{
                        Thread.sleep(500) ;    // 线程休眠
                }catch(InterruptedException e){}
                System.out.println(Thread.currentThread().getName()
                        + "运行,i = " + i) ;    // 取得当前线程的名字
            }
        }
    };
    public class demo1{
        public static void main(String args[]){
            MyThread mt = new MyThread() ;    // 实例化Runnable子类对象
            Thread t = new Thread(mt,"线程");        // 实例化Thread对象
            t.start() ;    // 启动线程
        }
    };
    复制代码

    会发现运行过程中,线程名是一个个间隔一定时间出来的,这里达到了休眠效果。

    复制代码
    线程运行,i = 0
    线程运行,i = 1
    线程运行,i = 2
    线程运行,i = 3
    线程运行,i = 4
    线程运行,i = 5
    线程运行,i = 6
    线程运行,i = 7
    线程运行,i = 8
    线程运行,i = 9
    线程运行,i = 10
    线程运行,i = 11
    线程运行,i = 12
    线程运行,i = 13
    线程运行,i = 14
    线程运行,i = 15
    线程运行,i = 16
    线程运行,i = 17
    线程运行,i = 18
    线程运行,i = 19
    线程运行,i = 20
    线程运行,i = 21
    线程运行,i = 22
    线程运行,i = 23
    线程运行,i = 24
    线程运行,i = 25
    线程运行,i = 26
    线程运行,i = 27
    线程运行,i = 28
    线程运行,i = 29
    线程运行,i = 30
    线程运行,i = 31
    线程运行,i = 32
    线程运行,i = 33
    线程运行,i = 34
    线程运行,i = 35
    线程运行,i = 36
    线程运行,i = 37
    线程运行,i = 38
    线程运行,i = 39
    线程运行,i = 40
    线程运行,i = 41
    线程运行,i = 42
    线程运行,i = 43
    线程运行,i = 44
    线程运行,i = 45
    线程运行,i = 46
    线程运行,i = 47
    线程运行,i = 48
    线程运行,i = 49
    复制代码

    3.6 线程的中断

      一个线程可以被另一个线程中断其操作的状态,使用 interrupt()方法完成。

    复制代码
    package Thread1;
    class MyThread implements Runnable{    // 实现Runnable接口
        public void run(){    // 覆写run()方法
            System.out.println("1、进入run()方法") ;
            try{
                    Thread.sleep(10000) ;    // 线程休眠10秒
                    System.out.println("2、已经完成了休眠") ;
            }catch(InterruptedException e){
                System.out.println("3、休眠被终止") ;
            }
            System.out.println("4、run()方法正常结束") ;
        }
    };
    public class demo1{
        public static void main(String args[]){
            MyThread mt = new MyThread() ;    // 实例化Runnable子类对象
            Thread t = new Thread(mt,"线程");        // 实例化Thread对象
            t.start() ;    // 启动线程
            try{
                    Thread.sleep(2000) ;    // 线程休眠2秒
            }catch(InterruptedException e){
                System.out.println("3、休眠被终止") ;
            }
            t.interrupt() ;    // 中断线程执行
        }
    };
    复制代码

    运行结果:

    1、进入run()方法
    3、休眠被终止
    4、run()方法正常结束

      会看到,在1到3的时候会因为线程休眠2秒而卡顿了一下。

      但是,既然线程中断了,那么4,这句话不应该打出来的,因此要在3,线程被终止处添加一句话rutrun,表示返回调用处

    复制代码
    package Thread1;
    class MyThread implements Runnable{    // 实现Runnable接口
        public void run(){    // 覆写run()方法
            System.out.println("1、进入run()方法") ;
            try{
                    Thread.sleep(10000) ;    // 线程休眠10秒
                    System.out.println("2、已经完成了休眠") ;
            }catch(InterruptedException e){
                System.out.println("3、休眠被终止") ;
                return ; // 返回调用处
            }
            System.out.println("4、run()方法正常结束") ;
        }
    };
    public class demo1{
        public static void main(String args[]){
            MyThread mt = new MyThread() ;    // 实例化Runnable子类对象
            Thread t = new Thread(mt,"线程");        // 实例化Thread对象
            t.start() ;    // 启动线程
            try{
                    Thread.sleep(2000) ;    // 线程休眠2秒
            }catch(InterruptedException e){
                System.out.println("3、休眠被终止") ;
            }
            t.interrupt() ;    // 中断线程执行
        }
    };
    复制代码

    运行结果:

    1、进入run()方法
    3、休眠被终止

    3.7 后台线程

      在Java中,只要一个线程没有执行完(一个线程在运行),则整个Java的进程不会消失,所以此时可以设置一个后台线程,这样即使java线程结束了,则后台线程

    依旧会继续执行。要想实现这个操作,要使用setDaemon()方法完成。

       t.setDaemon(true) ; 

    复制代码
    class MyThread implements Runnable{    // 实现Runnable接口
        public void run(){    // 覆写run()方法
         int i=0; while(true){    //设置死循环,这样来实现线程不断运行,设置后台运行。 System.out.println(Thread.currentThread().getName() + "在运行。"+i) ; } } }; public class ThreadDaemonDemo{ public static void main(String args[]){ MyThread mt = new MyThread() ; // 实例化Runnable子类对象 Thread t = new Thread(mt,"线程"); // 实例化Thread对象 t.setDaemon(true) ; // 此线程在后台运行 t.start() ; // 启动线程 } };
    复制代码

    3.8线程的优先级

      获取优先级的方法:getPriority();

      优先级分为最低,最高,普通三个(Thread.MIN_PRIORITY,Thread.MAX_PRIORITY,Thread.NORM_PRIORITY),

    设置优先级:

    MyThread  t1=new MyThread();
    Thread t3 = new Thread(t1,"线程C") ;//实例化线程对象
    t3.setPriority(Thread.MIN_PRIORITY) ;//设置优先级为最低

    例子:

    复制代码
    package Thread1;
    class MyThread implements Runnable{    // 实现Runnable接口
        public void run(){    // 覆写run()方法
            for(int i=0;i<5;i++){
                try{
                        Thread.sleep(500) ;    // 线程休眠
                }catch(InterruptedException e){}
                System.out.println(Thread.currentThread().getName()
                        + "运行,i = " + i) ;    // 取得当前线程的名字
            }
        }
    };
    public class demo1{
        public static void main(String args[]){
            Thread t1 = new Thread(new MyThread(),"线程A") ;    // 实例化线程对象
            Thread t2 = new Thread(new MyThread(),"线程B") ;    // 实例化线程对象
            Thread t3 = new Thread(new MyThread(),"线程C") ;    // 实例化线程对象
            t1.setPriority(Thread.MIN_PRIORITY) ;    // 优先级最低
            t2.setPriority(Thread.MAX_PRIORITY) ;    // 优先级最低
            t3.setPriority(Thread.NORM_PRIORITY) ;    // 优先级最低
            t1.start() ;    // 启动线程
            t2.start() ;    // 启动线程
            t3.start() ;    // 启动线程
        }
    };
     
    复制代码

    运行结果:

    复制代码
    线程B运行,i = 0
    线程C运行,i = 0
    线程A运行,i = 0
    线程B运行,i = 1
    线程C运行,i = 1
    线程A运行,i = 1
    线程B运行,i = 2
    线程A运行,i = 2
    线程C运行,i = 2
    线程B运行,i = 3
    线程C运行,i = 3
    线程A运行,i = 3
    线程B运行,i = 4
    线程C运行,i = 4
    线程A运行,i = 4
    复制代码

    主方法的优先级

      主方法的优先级是NORM_PRIORITY.

    复制代码
    package Thread1;
    public class demo1{
        public static void main(String args[]){
            System.out.println("主方法的优先级:" + 
                Thread.currentThread().getPriority()) ;    // 取得主方法的优先级
            System.out.println("MAX_PRIORITY = " + Thread.MAX_PRIORITY) ;
            System.out.println("NORM_PRIORITY = " + Thread.NORM_PRIORITY) ;
            System.out.println("MIN_PRIORITY = " + Thread.MIN_PRIORITY) ;
        }
    };
    复制代码

    运行结果:

    主方法的优先级:5
    MAX_PRIORITY = 10
    NORM_PRIORITY = 5
    MIN_PRIORITY = 1

      由此可知,主方法优先级是5,也就是普通优先级,而且主方法是一个线程对象。

    3.9 线程的礼让

      yield()方法实现线程的礼让。

    复制代码
    package Thread1;
    class MyThread implements Runnable{    // 实现Runnable接口
        public void run(){    // 覆写run()方法
            for(int i=0;i<5;i++){
                try{
                    Thread.sleep(500) ;  //休眠一下
                }catch(Exception e){}
                System.out.println(Thread.currentThread().getName()
                        + "运行,i = " + i) ;    // 取得当前线程的名字
                if(i==2){
                    System.out.print("线程礼让:") ;
                    Thread.currentThread().yield() ;    // 首先获取当前线程,然后线程礼让
                }
            }
        }
    };
    public class demo1{
        public static void main(String args[]){
            MyThread my = new MyThread() ;    // 实例化MyThread对象
            Thread t1 = new Thread(my,"线程A") ;
            Thread t2 = new Thread(my,"线程B") ;
            t1.start() ;
            t2.start() ;
        }
    };
    复制代码

    运行结果:

    复制代码
    线程A运行,i = 0
    线程B运行,i = 0
    线程B运行,i = 1
    线程A运行,i = 1
    线程A运行,i = 2
    线程礼让:线程B运行,i = 2
    线程礼让:线程A运行,i = 3
    线程B运行,i = 3
    线程A运行,i = 4
    线程B运行,i = 4
    复制代码
  • 相关阅读:
    漫谈 IP 协议
    Git常用组合操作
    my questions of C#
    关于C#多态的思考
    设计模式:示例与思考
    C#环境搭建,以及C#编译器的使用
    网络模型和TCP协议族
    Understanding TCP/IP Network Stack
    Get on the CORBA
    Introduction to COBRA
  • 原文地址:https://www.cnblogs.com/BlingSun/p/7484058.html
Copyright © 2011-2022 走看看