首页  >  文章  >  Java  >  java线程

java线程

伊谢尔伦
伊谢尔伦原创
2016-12-10 09:50:441190浏览

1,  Java中编写多线程程序和其他的编程语言相比容易很多。主要通过Runnable接口和Thread类来实现。

publicclassSimpleRunnable implements Runnable{
   private String message;
   publicstaticvoid main(String[] args) {
      SimpleRunnabler1 = new SimpleRunnable("Hello");
      Threadt1 = new Thread(r1);
      t1.start();
      for(;;){
         System.out.println("Bye-bye");
      }
   }
   public SimpleRunnable(String message){
      this.message = message;
   }
   @Override
   publicvoid run() {
      for(;;){
         System.out.println(message);
      }
   }
}

以上,通过继承于Runable接口实现run()来实现多线程,通过Thread来实现虚拟CPU,让线程r1在独立的线程中运行。事实上,该线程和主线程并不是完全的独立运行的线程,而是r1线程和主线程轮番切换运行,只是切换的运行速度特别快,看上去像是两个线程独立运行。

2,  线程的切换,根据不同的操作系统而有所不同:

一种是排队机制,如果一个线程抢得了CPU,直到该线程运行结束,或者被动停止才推出。

一种是通过优先级模式,优先级最高的线程优先抢到CPU。

一种是时间片,每一个线程拥有公平的时间片,当一个线程运行完时间片后退出,其他的线程拥有公平的机会抢占CPU。

Java的线程采用基于优先级和时间片综合的方式,具体实现根据运行的操作系统而有所不同。比如说当一个线程时间片运行完后退出并将优先级降一级,然后排序优先级比较高的线程抢占CPU,如果运行的过程中来了一个优先级更高的线程,则会抢占当前的CPU。

3,  线程运行状态:

线程停止(Pause)包括,sleep(),wait(),suspend(),I/O blocking

线程重启(Run)包括,sleep time-out,notify(),resume(),I/O finished

线程终止,stop()

线程等待,join()

线程主动让出CPU,yield()

以上suspend(),resume(),stop()都已过时,不再建议使用。

4,  其中sleep()函数是static的,是属于类的函数,而不是对象。该函数将使调用的线程暂停一定时间,而不是某一个其他的线程停止。如下

publicstaticvoidmain(String[] args)throwsException {
      SimpleRunnabler1 = new SimpleRunnable("Hello");
      Threadt1 = newThread(r1);
      t1.start();
      for(inti = 0; i < 10; i++){
         System.out.println("Bye-bye");
      }
      t1.sleep(10000);
      t1.stop();
}

以上代码是使主线程停止10秒钟,而不是使t1停止10秒钟。另外sleep()使线程暂停的时间是个模糊值,以上理论将使主线程暂停10秒钟,但是由于线程切换的不确定性,导致主线程并不是精确的暂停10秒钟。

5,  另外一个static的函数是yield(),他表示当前正在运行的线程主动让出CPU,该函数也是仅仅能作用于当前线程类似于以上sleep()函数。

6,  编程是为了追求高效的结果,采用多线程。但是多线程运行是很难预测的,因此我们会采取一定的方法,让多线程的运行结果尽量可预测。

class Thread1 extends Thread{
   @Override
   publicvoid run(){
      try{
         System.out.println("thread1 start");
         sleep(10000);                  // <3>
         System.out.println("thread1 finish");//<4>
      }catch(Exception e){
      }
   }
}
class Thread2 extends Thread{
   @Override
   publicvoid run(){
      try{
         System.out.println("thread2 start");
         suspend();                  // <2>
         System.out.println("thread2 finish");// <7>
      }catch(Exception e){
      }
   }
}
publicclassThreadTest {
 
   publicstaticvoid main(String[] args) {
      Threadt1 = new Thread1();
      Thread2t2 = new Thread2();
      t1.start();
      t2.start();
      try{
         System.out.println("s1");
         t1.join();                  // <1>
         System.out.println("s2");      // <5>
         t2.resume();                //<6>
         System.out.println("s3");      // <8>
         t2.join();                  // <9>
      }catch(Exception e){
      }
      System.out.println("s4");         // <10>
   }
}

以上运行其中一次的运行结果为:

thread1 start

thread2 start

s1

thread1 finish

s2

s3

thread2 finish

s4

但是并不是每次都得到这样的结果。但是也有一部分是可预测的。哪些是可预测的?哪些是不可预测的?

(1)       前三行一定会占据前三行,由于f35d6e602fd7d0f0edfa6f7d103c1b57的代码使主线程停止,等待线程t1运行结束,而t1线程在5bdf4c78156c7953567bb5a0aef2fc53处使线程暂停10秒钟,同时2cc198a1d5eb0d3eb508d858c9f5cbdb处代码是线程t2处于挂起状态,知道有代码唤醒该线程,否则该线程就会一直处于阻塞状态。但是前三行的输出顺序是不可预测的。

(2)      第四行一定会在第四行,当t1休眠结束后,首先运行23889872c2e8594e0f446a471a78ec4c处代码

(3)      第五行一定会在第五行,当t1线程运行结束后,主线程获得CPU开始运行代码43ad812d3a971134e40facaca816c822

(4)      第六行和第七行的位置可能会互换,当代码efbfa0de8737dc86eae413541a49df20唤醒线程t2后从40107655ec554331c1c6222ab67a141c开始运行,同时主线程继续运行37cd6113a8c348d99fa846f2c6fcea98

(5)      最后一行一定会在最后一行。在c161494dba5e0dd0fb25d890c74e408d暂停主线程,等待t2运行结束,运行eebe431eeb58984ec8915354762c30c6输出最后一行,主线程结束退出。


声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn