博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用多线程
阅读量:5970 次
发布时间:2019-06-19

本文共 6011 字,大约阅读时间需要 20 分钟。

        一个进程正在运行时至少会有1个线程在运行,这种情况在Java中也是存在的。这些线程在后台默默地执行,比如调用public static void main(String[] args)方法的线程就是这样的,而且它是由JVM创建的

        在Java的JDK开发包中,已经自带了对多线程的支持,可以很方便地进行多线程编程。实现多线程编程的方式主要有两种,一种是继承Thread类,另一种是实现Runnable接口,Thread类的结构如下:

      

       从上面的源代码中可以发现,Thread类实现了Runnable接口,他们之间具有多态关系。

       其实,使用继承Thread类的方式创建新线程时,最大的局限就是不支持多继承,因为Java语言的特点就是单根继承,所以为了支持多继承,完全可以实现Runnable接口的方式,一边实现一边继承。但用这两种方式创建的线程在工作时的性质是一样的,没有本质的区别。

       创建一个自定义的线程类MyThread.java,此类继承自Thread,并且重写run方法。  

1 package com.mythread.www; 2  3 public class MyThread extends Thread { 4      5     @Override 6     public void run() { 7         super.run(); 8         System.out.println("MyThread"); 9     }10     11 }

       运行类代码如下:

1 package test; 2  3 import com.mythread.www.MyThread; 4  5 public class Run { 6      7     public static void main(String[] args) { 8         MyThread myThread = new MyThread(); 9         myThread.start();10         System.out.println("运行结束!");11     }12 13 }

        运行结果如下:

       

        这行代码执行后,线程已处于就绪状态,但CPU还未分配时间片段给此线程,而是继续执行主线程main。

       从运行结果来看,MyThread.java类中的run方法执行的时间比较晚,这也说明在使用多线程技术时,代码的运行结果与代码执行顺序或调用顺序是无关的。

       线程是一个子任务,CPU以不确定的方式,或者说是以随机的时间来调用线程中的run方法,所以就会出现先打印 “运行结束!” 后输出 “MyThread” 这样的结果了。

       如果多次调用start()方法,则会出现如下异常:

 

1 package test; 2  3 import com.mythread.www.MyThread; 4  5 public class Run { 6      7     public static void main(String[] args) { 8         MyThread myThread = new MyThread(); 9         myThread.start();10         myThread.start();11         System.out.println("运行结束!");12     }13 14 }

 

    

       看下Thread类的源码就清楚了

      

        当第一次调用start()方法时,threadStatus初始值为0,表示线程还未开始执行,执行完start0()方法后,threadStatus的值将改变,不再为0,表示线程已经处于执行状态,当再次调用start()方法时,就会抛出上述异常。

--------------------------------------------------------------------------------------------------------------------------------

1 package test; 2  3 public class MyThread extends Thread { 4      5     @Override 6     public void run() { 7         for (int i = 0; i < 5; i++) { 8             int time = (int)(Math.random() * 1000); 9 //          System.out.println("myThreadTime:" + time);10             try {11                 Thread.sleep(time);12             } catch (InterruptedException e) {13                 // TODO Auto-generated catch block14                 e.printStackTrace();15             }16             System.out.println("myThread=" + Thread.currentThread().getName());17         }18     }19 20 }
1 package test; 2  3 public class Test { 4      5     public static void main(String[] args) { 6         MyThread myThread = new MyThread(); 7         myThread.setName("myThread"); 8         myThread.start(); 9 //      myThread.run();10         for (int i = 0; i < 5; i++) {11             int time = (int)(Math.random() * 1000);12 //          System.out.println("mainTime:" + time);13             try {14                 Thread.sleep(time);15             } catch (InterruptedException e) {16                 // TODO Auto-generated catch block17                 e.printStackTrace();18             }19             System.out.println("main=" + Thread.currentThread().getName());20         }21     }22     23 }

上述代码执行后的结果如下:

myThread.run()这段代码的注释去掉,再把myThread.start()注释掉后,运行的结果如下:

      Thread.java类中的start()方法通知“线程规划器”此线程已经准备就绪,等待调用线程对象的run()方法。这个过程其实就是让系统安排一个时间来调用Thread中的run()方法,也就是使线程得到运行,启动线程,具有异步执行的效果。如果调用代码myThread.run()就不是异步执行了,而是同步,那么此线程对象并不给“线程规划器”来进行处理,而是由main主线程来调用run()方法,也就是必须等run()方法中的代码执行完后才可以执行后面的代码。

       另外需要注意的是,执行start()方法的顺序不代表线程启动的顺序。

1 package test; 2  3 public class Test { 4      5     public static void main(String[] args) { 6         MyThread t0 = new MyThread(0); 7         MyThread t1 = new MyThread(1); 8         MyThread t2 = new MyThread(2); 9         MyThread t3 = new MyThread(3);10         MyThread t4 = new MyThread(4);11         MyThread t5 = new MyThread(5);12         MyThread t6 = new MyThread(6);13         MyThread t7 = new MyThread(7);14         MyThread t8 = new MyThread(8);15         MyThread t9 = new MyThread(9);16         t0.start();17         t1.start();18         t2.start();19         t3.start();20         t4.start();21         t5.start();22         t6.start();23         t7.start();24         t8.start();25         t9.start();    26     }27     28 }

执行上述代码后,运行结果如下:

--------------------------------------------------------------------------------------------------------------------------------

       如果欲创建的线程类已经有一个父类了,这时就不能再继承自Thread类了,因为Java不支持多继承,所以就需要实现Runnable接口来应对这种情况。

1 package test; 2  3 public class MyRunnable implements Runnable { 4      5     @Override 6     public void run() { 7         System.out.println("运行中!"); 8     } 9 10 }

       如何使用这个MyRunnable.java类呢?这就要看下Thread.java的构造函数了,如下图所示,其中三角符号标识的是default构造函数,其它的均为public构造函数

1 package test; 2  3 public class Run { 4      5     public static void main(String[] args) { 6         MyRunnable myRunnable = new MyRunnable(); 7         Thread thread = new Thread(myRunnable); 8         thread.start(); 9         System.out.println("运行结束!");10     }11 12 }

运行上述代码后,结果如下:

 

另外需要说明的是,Thread.java类也实现了Runnable接口,那就意味着构造函数Thread(Runnable target)不光可以传入Runnable接口的对象,还可以传入一个Thread类的对象,这样做完全可以将一个Thread对象中的run()方法交由其他的线程进行调用。

--------------------------------------------------------------------------------------------------------------------------------

实例变量与线程安全

1、不共享数据的情况

1 package thread; 2  3 public class MyThread extends Thread { 4      5     private int count = 5; 6      7     public MyThread(String name) { 8         super(); 9         this.setName(name);10     }11     12     @Override13     public void run() {14         while (count > 0) {15             count--;16             System.out.println(this.currentThread().getName() +17                     ":count = " + count);18         }    19     }20     21     public static void main(String[] args) {22         MyThread a = new MyThread("A");23         MyThread b = new MyThread("B");24         MyThread c = new MyThread("C");25         a.start();26         b.start();27         c.start();28     }29 30 }

 

执行上述代码运行结果如下:

从运行结果可以看出,每个线程都有各自的count变量,自己减少自己的count变量的值。这样的情况就是变量不共享,此示例并不存在多个线程访问同一个实例变量的情况。

2、共享数据的情况

 

转载于:https://www.cnblogs.com/hanw1991/p/7487055.html

你可能感兴趣的文章
Laravel 5.1 artisan 的使用
查看>>
Maven 学习之旅
查看>>
C Primer Plus 第5章 运算符、表达式和语句 编程练习及答案
查看>>
Python点滴
查看>>
WINDOWS 几种坐标系
查看>>
大豆和黄豆芽还能吃吗?
查看>>
Yii2中如何将Jquery放在head中的方法
查看>>
解析solidity的event log
查看>>
[转发] 【GRT安智网】HTC安致手机ROM国内首个中文定制教程goapk首发[最新厨房V0......
查看>>
try catch 之后是否会继续执行
查看>>
vim 配置svn
查看>>
《重构-改善既有代码设计》读书笔记-重构篇
查看>>
测试第三方代码
查看>>
RabbitMQ接触(二)
查看>>
Springboot-添加对jsp支持
查看>>
数据库设计中的14个技巧
查看>>
替换k个字符后最长重复子串
查看>>
讲解sed用法入门帖子
查看>>
Java异常学习心得
查看>>
Scala学习之类和属性篇(一):定义类的主构造方法
查看>>