【Java】java基础之多线程

多线程

概念: 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

生命周期:

img

  • 新建状态:

    使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。

  • 就绪状态:

    当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。

  • 运行状态:

    如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

  • 阻塞状态:

    如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:

    • 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
    • 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
    • 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
  • 死亡状态:

    一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。

线程的优先级:

取值范围是 1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )

默认情况下,每一个线程都会分配一个优先级 NORM_PRIORITY(5)。

线程的创建:

  • 通过实现 Runnable 接口;
  • 通过继承 Thread 类本身;
  • 通过 Callable 和 Future 创建线程。

1.通过实现 Runnable 接口

class RunnableDemo implements Runnable {
    
    
   private Thread t;
   private String threadName;
   
   RunnableDemo( 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[]) {
    
    
      RunnableDemo R1 = new RunnableDemo( "Thread-1");
      R1.start();
      
      RunnableDemo R2 = new RunnableDemo( "Thread-2");
      R2.start();
   }   
}

运行结果:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

2.通过继承Thread来创建线程

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();
   }   
}

运行结果:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

Thread 方法

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

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

测试线程是否处于活动状态。 上述方法是被Thread对象调用的。下面的方法是Thread类的静态方法。

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

通过 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;  
    }  
}


使用匿名内部类创建线程:

/*
 * 匿名内部类的格式:
 */
public class ThreadDemo {
    
    
    public static void main(String[] args) {
    
    
        // 继承thread类实现多线程
        new Thread() {
    
    
            public void run() {
    
    
                for (int x = 0; x < 100; x++) {
    
    
                    System.out.println(Thread.currentThread().getName() + "--"
                            + x);
                }
            }
        }.start();
        ;

        // 实现runnable借口,创建多线程并启动
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                for (int x = 0; x < 100; x++) {
    
    
                    System.out.println(Thread.currentThread().getName() + "--"
                            + x);
                }
            }
        }) {
    
    
        }.start();

        // 更有难度的,在Thread匿名内部类的里面再一次重写run方法
        //在实际运行时的结果是 hello+x。以thread的run方法为准。但是此处无意义
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                // TODO Auto-generated method stub
                for (int x = 0; x < 100; x++) {
    
    
                    System.out.println("java" + "--" + x);
                }

            }
        }) {
    
    
            public void run() {
    
    
                for (int x = 0; x < 100; x++) {
    
    
                    System.out.println("hello" + "--" + x);
                }
            }
        }.start();
    }
}

*声明:此博文为本人学习笔记,参考菜鸟教程等网络资源,如果侵权,请私信告知!*

猜你喜欢

转载自blog.csdn.net/qq_42380734/article/details/105387830