多线程

多线程

并发与并行

并发:指两个或多个事件在同一个时间段内发生。

并行:指两个或多个事件在同一个时刻发生(同时发生)。

进程与线程

进程:指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。进入到内存中的程序。

线程:线程是进程的一个执行的单位,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程 中是可以有多个线程的,这个应用程序也可以称为多线程程序。

简之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程。

Thread

  • public class Thread
    extends Object
    implements Runnable

    线程是程序中执行的线程。Java虚拟机允许应用程序同时执行多个执行线程。

    每个线程都有优先权。 具有较高优先级的线程优先于优先级较低的线程执行。 每个线程可能也可能不会被标记为守护程序。 当在某个线程中运行的代码创建一个新的Thread对象时,新线程的优先级最初设置为等于创建线程的优先级,并且当且仅当创建线程是守护进程时才是守护线程。

    当Java虚拟机启动时,通常有一个非守护进程线程(通常调用某些指定类的名为main的方法)。 Java虚拟机将继续执行线程,直到发生以下任一情况:

    • 已经调用了Runtime类的exit方法,并且安全管理器已经允许进行退出操作。

    • 所有不是守护进程线程的线程都已经死亡,无论是从调用返回到run方法还是抛出超出run方法的run

    创建一个新的执行线程有两种方法。 一个是将一个类声明为Thread的子类。 这个子类应该重写run类的方法Thread 。 然后可以分配并启动子类的实例。 例如,计算大于规定值的素数的线程可以写成如下:


    class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }


    然后,以下代码将创建一个线程并启动它运行:

    PrimeThread p = new PrimeThread(143); p.start();

    另一种方法来创建一个线程是声明实现类Runnable接口。 那个类然后实现了run方法。 然后可以分配类的实例,在创建Thread时作为参数传递,并启动。 这种其他风格的同一个例子如下所示:


    class PrimeRun implements Runnable { long minPrime; PrimeRun(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }


    然后,以下代码将创建一个线程并启动它运行:

    PrimeRun p = new PrimeRun(143); new Thread(p).start();

    每个线程都有一个用于识别目的的名称。 多个线程可能具有相同的名称。 如果在创建线程时未指定名称,则会为其生成一个新名称。

    除非另有说明,否则将null参数传递给null中的构造函数或方法将导致抛出NullPointerException

image-20200504210103641

public class Thread01 extends Thread{
   private String name;

   public Thread01(String name) {
       this.name = name;
  }

   public Thread01() {
  }

   @Override
   public void run() {
       for (int i = 0; i < 20; i++) {
           System.out.println("extends Thread"+i);
      }
  }
}
public class Thread02 implements Runnable {
   private Integer age;

   public Thread02() {
  }

   public Thread02(Integer age) {
       this.age = age;
  }

   @Override
   public void run() {
       for (int i = 0; i < 20; i++) {
           System.out.println("implements Runnable"+i);
      }
  }
}
public class ThreadMain {
   public static void main(String[] args) {
       Thread01 haha = new Thread01("haha");
       haha.start();

       Thread02 thread02 = new Thread02(18);
       new Thread(thread02).start();

       for (int i = 0; i < 20; i++) {
           System.out.println("main"+i);
      }
  }
}

image-20200504210803684

常用方法:

    • getName() 返回此线程的名称。

    • run()如果这个线程使用单独的Runnable运行对象构造,则调用该Runnable对象的run`方法; 否则,此方法不执行任何操作并返回。

    • sleep(long millis)` 使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。

    • start()导致此线程开始执行; Java虚拟机调用此线程的run方法。

    • currentThread() 返回对当前正在执行的线程对象的引用。

/**
* @program: intellij idea
* @description:定义一个thread子类
* @author: lixy
* @create: 2020-05-04 21:18
**/
public class MyThread01 extends Thread {
  @Override
  public void run() {//重写run方法
      String name = getName();
      System.out.println("MyThread01线程名称:"+name);
      Thread thread = MyThread01.currentThread();
      System.out.println(thread);
      System.out.println(Thread.currentThread().getName());
  }
}
public class Demo02Sleep {
  public static void main(String[] args) {
      for (int i = 1; i <= 60; i++) {
          System.out.println(i);

          //使用thread类的sleep方法让程序睡眠
          try {
              Thread.sleep(1000);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
  }
}

实现Runnable接口创建多线程的好处:

1、避免了单继承的局限性

一个类只能继承一个类,类继承了Thread类就不能继承其他的类

实现Runnable接口,还可以继承其他的类,实现其他的接口。

2、增强了程序的扩展性,降低了程序的耦合性(解耦)

实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离(解耦)

实现类中,重写了run方法,用来设置线程任务

创建Thread类对象,调用start方法,用来开启新线程。

线程同步

方法:

1、同步代码块

2、同步方法

3、锁机制

image-20200504234834103

/**
* @program: intellij idea
* @description:实现卖票
* @author: lixy
* @create: 2020-05-04 22:02
**/
public class RunnableImpl implements Runnable {
  private static ArrayList<String> tickets = new ArrayList<String>(Arrays.asList("1号","2号","3号","4号","5号","6号","7号","8号"));
  //创建一个锁对象
  private Object obj = new Object();
  //3-1、在成员位置创建一个
  private Lock lock = new ReentrantLock();
  //设置线程任务:卖票
  @Override
  public void run() {
      //1同步代码块
      /*synchronized (obj){
          //先判断票是否存在
          if (tickets.size()>0){
              int i = new Random().nextInt(tickets.size());
              String ticket = tickets.get(i);
              if (tickets.contains(ticket)){
                  tickets.remove(ticket);
                  System.out.println(Thread.currentThread().getName()+"——存在:"+ticket);
              }
          }
      }*/

      //2、同步方法
      /*metho();*/

      //3、锁机制Lock锁
      lock.lock();//3-2枷锁
      try {
          if (tickets.size()>0){
              int i = new Random().nextInt(tickets.size());
              String ticket = tickets.get(i);
              if (tickets.contains(ticket)){
                  tickets.remove(ticket);
                  System.out.println(Thread.currentThread().getName()+"——存在:"+ticket);
              }
          }
      } catch (Exception e) {
          e.printStackTrace();
      } finally {
          lock.unlock();//3-3解锁
      }
  }
  public /*static*/ synchronized void metho(){//静态同步方法
      if (tickets.size()>0){
          int i = new Random().nextInt(tickets.size());
          String ticket = tickets.get(i);
          if (tickets.contains(ticket)){
              tickets.remove(ticket);
              System.out.println(Thread.currentThread().getName()+"——存在:"+ticket);
          }
      }
  }
}

image-20200505000423813

Wait(等待)与Notify(唤醒)

    • voidnotify() 唤醒正在等待对象监视器的单个线程。
      void notifyAll() 唤醒正在等待对象监视器的所有线程。
      String toString() 返回对象的字符串表示形式。
      void wait() 导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。
      void wait(long timeout) 导致当前线程等待,直到另一个线程调用 notify()方法或该对象的 notifyAll()方法,或者指定的时间已过。
      void wait(long timeout, int nanos) 导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法,或者某些其他线程中断当前线程,或一定量的实时时间。
public class Demo04WaitAndNotify {
   public static void main(String[] args) {
       //锁对象
       Object o = new Object();
       new Thread(){
           @Override
           public void run() {
               synchronized (o){
                   System.out.println("等待。。。");
                   try {
                       o.wait();//等待
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
                   System.out.println("开吃。。。");
              }
          }
      }.start();
       new Thread(){
           @Override
           public void run() {
               synchronized (o){
                   System.out.println("唤醒。。。");
                   o.notify();//唤醒
              }
          }
      }.start();
  }
}
运行结果:
等待。。。
唤醒。。。
开吃。。。

 

原文地址:https://www.cnblogs.com/lxy522/p/12829809.html