侧边栏壁纸

JAVA 的多线程编程

2024年03月04日 277阅读 0评论 1点赞

java的多线程编程

下图展示了 java 线程的生命周期
java-thread.jpg
当我们只调用 run()方法时,线程并不会被启动,只会执行 run();只有当调用 start()方法时,线程才会被启动,并且调用 run()方法;
我们常用的 public static void main(String[] args) main 其实是 java 中的主线程。

java创建线程的三种方式

通过实现 Runnable 接口
创建一个线程,最简单的方法是创建一个实现 Runnable 接口的类。
为了实现 Runnable,一个类只需要执行一个方法调用 run(),声明如下:

public void run()

你可以重写该方法,重要的是理解的 run() 可以调用其他方法,使用其他类,并声明变量,就像主线程一样。
在创建一个实现 Runnable 接口的类之后,你可以在类中实例化一个线程对象。
Thread 定义了几个构造方法,下面的这个是我们经常使用的:


教程参考菜鸟教程
Thread(Runnable threadOb,String threadName);

这里,threadOb 是一个实现 Runnable 接口的类的实例,并且 threadName 指定新线程的名字。
新线程创建之后,你调用它的 start() 方法它才会运行。
通过继承 Thread 类本身
创建一个线程的第二种方法是创建一个新的类,该类继承 Thread 类,然后创建一个该类的实例。
继承类必须重写 run() 方法,该方法是新线程的入口点。它也必须调用 start() 方法才能执行。
该方法尽管被列为一种多线程实现方式,但是本质上也是实现了 Runnable 接口的一个实例。

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   
   ThreadDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // 让线程睡眠一会
            Thread.sleep(50);
         }
      }catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}
 
public class TestThread {
 
   public static void main(String args[]) {
      ThreadDemo T1 = new ThreadDemo( "Thread-1");
      T1.start();
      
      ThreadDemo T2 = new ThreadDemo( "Thread-2");
      T2.start();
   }   
}

下表列出了Thread类的一些重要方法:

序号方法描述
1.使该线程开始执行;Java 虚拟机调用该线程的 run 方法public void start();
2.如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回public void run();
3.改变线程名称,使之与参数 name 相同。public final void setName(String name);
4.更改线程的优先级。public final void setPriority(int priority);
5.将该线程标记为守护线程或用户线程。public final void setDaemon(boolean on);
6.等待该线程终止的时间最长为 millis 毫秒。public final void join(long millisec);
7.中断线程。public void interrupt();
8.测试线程是否处于活动状态。public final boolean isAlive();

上述方法是被 Thread 对象调用的,下面表格的方法是 Thread 类的静态方法。

序号方法描述
1.暂停当前正在执行的线程对象,并执行其他线程。public static void yield()
2.在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。public static void sleep(long millisec)
3.当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。public static boolean holdsLock(Object x)
4.返回对当前正在执行的线程对象的引用。public static Thread currentThread()
5.将当前线程的堆栈跟踪打印至标准错误流。public static void dumpStack()

方法演示

// 文件名 : DisplayMessage.java
// 通过实现 Runnable 接口创建线程
public class DisplayMessage implements Runnable {
   private String message;
   
   public DisplayMessage(String message) {
      this.message = message;
   }
   
   public void run() {
      while(true) {
         System.out.println(message);
      }
   }
}
// 文件名 : GuessANumber.java
// 通过继承 Thread 类创建线程
 
public class GuessANumber extends Thread {
   private int number;
   public GuessANumber(int number) {
      this.number = number;
   }
   
   public void run() {
      int counter = 0;
      int guess = 0;
      do {
         guess = (int) (Math.random() * 100 + 1);
         System.out.println(this.getName() + " guesses " + guess);
         counter++;
      } while(guess != number);
      System.out.println("** Correct!" + this.getName() + "in" + counter + "guesses.**");
   }
}
// 文件名 : ThreadClassDemo.java
public class ThreadClassDemo {
 
   public static void main(String [] args) {
      Runnable hello = new DisplayMessage("Hello");
      Thread thread1 = new Thread(hello);
      thread1.setDaemon(true);
      thread1.setName("hello");
      System.out.println("Starting hello thread...");
      thread1.start();
      
      Runnable bye = new DisplayMessage("Goodbye");
      Thread thread2 = new Thread(bye);
      thread2.setPriority(Thread.MIN_PRIORITY);
      thread2.setDaemon(true);
      System.out.println("Starting goodbye thread...");
      thread2.start();
 
      System.out.println("Starting thread3...");
      Thread thread3 = new GuessANumber(27);
      thread3.start();
      try {
         thread3.join();
      }catch(InterruptedException e) {
         System.out.println("Thread interrupted.");
      }
      System.out.println("Starting thread4...");
      Thread thread4 = new GuessANumber(75);
      
      thread4.start();
      System.out.println("main() is ending...");
   }
}

通过 Callable 和 Future 创建线程

  1. 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。
  2. 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
  3. 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
  4. 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。

    public class CallableThreadTest implements Callable<Integer> {
     public static void main(String[] args)  
     {  
         CallableThreadTest ctt = new CallableThreadTest();  
         FutureTask<Integer> ft = new FutureTask<>(ctt);  
         for(int i = 0;i < 100;i++)  
         {  
             System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);  
             if(i==20)  
             {  
                 new Thread(ft,"有返回值的线程").start();  
             }  
         }  
         try  
         {  
             System.out.println("子线程的返回值:"+ft.get());  
         } catch (InterruptedException e)  
         {  
             e.printStackTrace();  
         } catch (ExecutionException e)  
         {  
             e.printStackTrace();  
         }  
      
     }
     @Override  
     public Integer call() throws Exception  
     {  
         int i = 0;  
         for(;i<100;i++)  
         {  
             System.out.println(Thread.currentThread().getName()+" "+i);  
         }  
         return i;  
     }  
    }
1
打赏

—— 评论区 ——

昵称
邮箱
网址
取消
人生倒计时
舔狗日记