复习JavaDay07

线程的5种状态

新生状态:Thread thread = new Thread();

就绪状态:当调用start()方法,线程立即进入就绪状态,但并不以为着立即调度执行

运行状态:进入运行状态,线程才真正执行线程体的代码块。

阻塞状态:当调用sleep(),wait或者同步锁时,线程进入阻塞状态,就是代码不往下执行

阻塞事件解除后,重新进入就绪状态,等待cpu调度执行。

死亡状态:(dead):线程中断或者结束,一旦进入死亡状态,就不能再次启动。

线程的常用方法

方法说明
setPriority(int newPriority); 更改线程优先级
static void sleep(long millis); 在指定的毫秒数内让当前正在执行的线程休眠
void join(); 等待该线程终止
static void yield(); 暂停当前正在执行的线程对象,并执行其他线程
void intrrupt(); 中断线程,别用这个方式
boolean isAlive(); 测试线程是否处于活动状态

自定义标识位结束线程:案例

不推荐使用JDK提供的stop()和destroy(),推荐线程自己停下来,设置一个变量,例如flag = false,则终止线程。

//设置标识位让线程在指定次数停止
public class TestThreadStop implements Runnable {
  private boolean flag = true;

  @Override
  public void run() {
      int i = 0;
      //这里执行循环
      while (flag) {
          System.out.println(Thread.currentThread().getName() + "运行了第" + i++ + "次");
      }
  }

  public boolean stop() {
      return this.flag = false;
  }

  public static void main(String[] args) {
      //错误示例:原因,在调用sotp方法时就需要new,和现在这个对象不是同一对象了,将陷入死循环
      //new Thread(new TestThreadWay(),"自定义线程").start();

      TestThreadStop t = new TestThreadStop();
      Thread thread = new Thread(t, "自定义线程");
      thread.start();

      //当main线程运行900次时结束掉自定义线程
      for (int i = 0; i < 1000; i++) {
          if (i == 900) {
              System.out.println(Thread.currentThread().getName()+"线程结束了====================");
              t.stop();
              break;
          }
          System.out.println("main------=========" + i);
      }
  }
}

sleep实现计时器案例:

public class TestThreadSleep implements Runnable {

  @Override
  public void run() {
      int time = 0;
      while (true) {
          try {
              Thread.sleep(1000);
              System.out.println(time++);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          if (time == 60) {
              System.out.println("1分钟结束,计时停止");
              break;
          }
      }

  }

  public static void main(String[] args) {
      new Thread(new TestThreadSleep()).start();
  }
}

join() 合并线程:举例线程插队

package com.softeem;

//合并线程 join()
public class TestThreadSleep implements Runnable {

  @Override
  public void run() {
      for (int i = 0; i < 100; i++) {
          System.out.println("Vip来了" + i);
      }


多线程模拟抢票

package com.softeem;

//模拟三个人抢票,保证线程安全
public class Simulation {
  public static void main(String[] args) {
      //新建三条线程
      TicketGrabbing t = new TicketGrabbing();
      new Thread(t, "小明").start();
      new Thread(t, "小红").start();
      new Thread(t, "黄牛").start();
  }
}

class TicketGrabbing implements Runnable {
  //定义票的总数
  private int icket = 1000;
  //定义定制参数
  private boolean flag = true;

  @Override
  public void run() {
      while (flag) {
          stop();
      }
  }

  //停止线程方法:注意,锁要加在使用的同步数据中,否则会失效
  public synchronized boolean stop() {
      try {
          Thread.sleep(100);
      } catch (InterruptedException e) {
          e.printStackTrace();
      }
      if (icket > 0) {
          System.out.println(Thread.currentThread().getName() + "抢到了第" + icket);
          icket--;
          return flag = true;
      } else {
          return flag = false;
      }
  }
}

线程同步块案例

//把ArrayList改成线程安全的(使用线程同步块)
public class Damo {

  public static void main(String[] args) {
      //创建两根线程同时执行
      NewTest newTest = new NewTest();
      new Thread(newTest, "线程1").start();
      new Thread(newTest, "线程2").start();
  }
}

class NewTest implements Runnable {
  //定义线程结束变量
  private boolean flag = true;
  //定义总执行次数
  private int a = 10_0000;
  //创建List数组对象
  List list = new ArrayList<>();

  @Override
  public void run() {
      while (flag) {
          add();
      }
  }

  public boolean add() {
      //同步代码块,this为当前类
      synchronized (this) {
          //如果执行次数大于0就继续执行
          if (a > 0) {
              System.out.println(Thread.currentThread().getName() + "存入了" + a);
              list.add(a);
              a--;
              return flag = true;
          } else {
              //否则就结束方法
              System.out.println(list.size());
              return flag = false;
          }
      }
  }
}

死锁避免方法

产生死锁的四个必要条件:
1. 互条件:一个资源每次只能被一个进程使用
2 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放3 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺
4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

lock锁(推荐)

ReentrantLock可重入锁

package com.softeem;

import java.util.concurrent.locks.ReentrantLock;

//三个人抢票,使用Lock
public class TestLock {
  public static void main(String[] args) {
      Ticket t = new Ticket();
      new Thread(t, "线程1").start();
      new Thread(t, "线程2").start();
      new Thread(t, "线程3").start();
  }
}

class Ticket implements Runnable {
  //定义票总数为100
  private int ticket = 10;
  //创建Lock锁对象
  private final ReentrantLock lock = new ReentrantLock();

  @Override
  public void run() {
      while (true) {
          //lock锁在try,catch,finally中执行,最后需要释放锁资源
          try {
              //开启lock
              lock.lock();
              //睡眠1ms
              Thread.sleep(500);
              if (ticket > 0) {
                  System.out.println(Thread.currentThread().getName() + "抢到了第" + ticket);
                  ticket--;
              } else {
                  return;
              }
          } catch (Exception e) {
              e.printStackTrace();
          } finally {
              //关闭lock
              lock.unlock();
          }
      }
  }
}

synchronized与Lock的对比 Lock是显式锁 (手动开启和关闭锁,别忘记关闭锁) synchronized是隐式锁,出了 作用域自动释放 Lock只有代码块锁,synchronized有代码块锁和方法锁 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展 性 (提供更多的子类 优先使用顺序: Lock 同步代码块 (已经进入了方法体,分配了相应资源)->同步方法 (在方法体之外)

生产者与消费者之红绿灯标示法

package com.softeem;

//测试生产者和消费者,红绿灯法(演员:观众:产品)
public class TestPC2 {
  public static void main(String[] args) {
      //实例化TV类
      TV tv = new TV();
      //实例化演员类,参数为产品类
      Player p = new Player(tv);
      //实例化观众类,参数为产品类
      Watcher w = new Watcher(tv);
      new Thread(p).start();
      new Thread(w).start();
  }
}

//演员类
class Player implements Runnable {
  TV tv;

  public Player(TV tv) {
      this.tv = tv;
  }

  @Override
  public void run() {
      //如果是双数表演快乐大本营,单数表演抖音短视频
      for (int i = 0; i < 20; i++) {
          if (i % 2 == 0) {
              this.tv.play("快乐大本营");
          } else {
              this.tv.play("抖音短视频");
          }
      }
  }
}

//观众类
class Watcher implements Runnable {
  TV tv;

  public Watcher(TV tv) {
      this.tv = tv;
  }

  @Override
  public void run() {
      for (int i = 0; i < 20; i++) {
          tv.watch();
      }
  }
}

//这里需要判断逻辑,观众观看时演员等待,演员表演时观众等待,
//如果没有节目,需要演员先去表演了观众才可以观看
class TV {
  //设置标志位,true时观众观看,false时演员表演
  private boolean flag = true;

  //节目
  private String voice;

  //演员表演方法及逻辑
  public synchronized void play(String voice) {
      //如果标志位为假演员等待(观众观看),为真就执行表演
      if (!flag) {
          try {
              //观众观看,当前线程等待
              this.wait();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
      //演员表演,节目是我传进来的
      System.out.println("演员表演了节目-->:" + voice);
      //通知唤醒其他线程
      this.notifyAll();
      //传进来的节目赋值给定义的节目
      this.voice = voice;
      //标志位取反改为false,false时说明演员已经表演完,观众可以观看了
      this.flag = !this.flag;
  }

  //观众观看方法及逻辑
  public synchronized void watch() {
      //如果标志位为真观众等待(演员表演),为假就执行观看
      if (flag) {
          try {
              //演员表演,当前线程等待
              this.wait();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
      //观众观看,节目演员表演完传递过来的
      System.out.println("观众观看了节目:" + voice);
      //通知唤醒其他线程
      this.notifyAll();
      //标志位取反改为true
      this.flag = !this.flag;
  }
}

创建线程池

//创建线程池:参数为线程数量
ExecutorService service = Executors.newFixedThreadPool(10);

1.创建线程池,2.编写要执行的类,3.关闭线程链接。

package com.softeem;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//测试线程池
public class TestThreadPool {
  public static void main(String[] args) {

      //创建线程池:参数为线程数量
      ExecutorService service = Executors.newFixedThreadPool(10);
      //创建线程,参数为执行对象
      service.execute(new Test());
      service.execute(new Test());
      service.execute(new Test());
      //关闭线程链接
      service.shutdown();
  }
}

class Test implements Runnable {

  @Override
  public void run() {
      System.out.println(Thread.currentThread().getName());
  }
}
 

  }

  public static void main(String[] args) throws InterruptedException {
      TestThreadSleep t = new TestThreadSleep();
      Thread t1 = new Thread(t);
      t1.start();

      //join()方法实现线程插队,注意:执行较小任务时不适用,会存在争夺时间片问题提前插队
      for (int i = 0; i < 500; i++) {
          System.out.println("排队" + i);
          if (i == 50) {
              t1.join();
          }
      }
  }
}
posted @   再叙旧  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示