欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  Java

java线程

程序员文章站 2022-04-06 10:34:32
...
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) 前三行一定会占据前三行,由于<1>的代码使主线程停止,等待线程t1运行结束,而t1线程在<3>处使线程暂停10秒钟,同时<2>处代码是线程t2处于挂起状态,知道有代码唤醒该线程,否则该线程就会一直处于阻塞状态。但是前三行的输出顺序是不可预测的。

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

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

(4) 第六行和第七行的位置可能会互换,当代码<6>唤醒线程t2后从<7>开始运行,同时主线程继续运行<8>

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

相关标签: java java线程