线程

2026年9月19日星期六·9923 字·50 分钟·
-浏览量
JavaJava并发API线程
AI 摘要- DeepSeek

线程是进程中的单个顺序执行流,是一条执行路径。一个进程如果只有一条执行路径,则成为单线程程序;而如果有多条执行路径,则成为多线程程序。

线程 - 封面图

线程#

概念

线程是进程中的单个顺序执行流,是一条执行路径。一个进程如果只有一条执行路径,则成为单线程程序;而如果有多条执行路径,则成为多线程程序。

CPU分时调度

时间片,即CPU分配给各个程序的时间,每个进程被分配一个时间段,称作它的时间片。即该进程允许运行的时间,使各个程序从表面上看是同时进行的。

如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程,将当前进程挂起。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换,而不会造成CPU资源浪费。当又切换到之前执行的进程,把现场恢复,继续执行。

在宏观上:我们可以同时打开多个应用程序,每个程序并行,同时运行。

在微观上:由于只有一个CPU,一次只能处理程序要求的一部分,如何处理公平,一种方法就是引入时间片,每个程序轮流执行。多核提高了并发能力。

单核CPU和多核CPU(了解):

单核CPU同时只能干一件事情,当启动多个程序时,CPU快速切换轮流处理每个程序,但如果CPU不够强劲,同时排队等待处理的任务太多,就会感觉系统会有延时、反应慢、卡顿等,甚至某一个程序在处理时出现错误,无法响应了,会造成后面排队的其他任务只能等待。

多核CPU是在基板上集成多个单核CPU+任务分配系统,两个核心同时处理两份任务,相比单核执行速度更快,有利于同时运行多个程序,不容易造成卡顿,更流畅!

Java程序的运行过程:

  1. 通过eclipse(java命令)运行一个Java程序,java命令会启动JVM(java虚拟机),等于启动了一个应用程序,也就是启动了一个进程。
  2. 该进程会自动启动一个“主线程”,然后主线程去调用某个类的 main 方法,所以 main 方法运行在主线程中。在此之前的所有程序代码都是按照顺序依次调用的,都是单线程的。

如果希望程序中实现多段程序代码交替执行的效果,则需要创建多线程程序。

为什么要使用多线程?

  • 单线程程序执行时都只有一条顺序执行流,如果程序执行某行代码时遇到了阻塞(比如:抛异常),那么程序的运行将会停滞在这一行,其他代码将会无法执行!

  • 这就像去银行办理业务,只有1个业务窗口(单线程),所有的客户都需要在一个窗口排队办理业务,如果业务员在为某一个客户办理业务时,花费了很长时间,那么将会导致后面的客户等待很长时间,这样处理业务的效率也是非常低的。

  • 但如果银行为了提高效率,同时开放了5个窗口(多线程),客户可以分布在这5个窗口分别办理业务,即使某一个窗口在为个别客户办理业务时花费了很长时间,但不影响其他窗口办理业务的进度。

多线程理解起来其实非常简单:

  • 单线程的程序只有一个顺序执行流。
  • 多线程的程序则可以包括多个顺序执行流,多个顺序流之间互不干扰。

[并行]和[并发]的区别: (这是两个概念)

  1. 并行执行指在同一时刻,有多条指令在多个处理器上同时执行;
  2. 并发执行指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。

多线程的特性#

随机性

多线程的程序在执行时,在某一时间点具体执行哪个线程是不确定的,可以确定的是某一个时间点只有一个线程在执行(单核CPU)。

虽然我们感觉这些线程像是在同时运行,实际上是因为CPU在快速切换轮流执行这些线程,由于切换速度是纳秒级别的,所以我们感觉不到。

如何实现多线程#

由于线程是依赖进程存在的,因此首先需要创建一个进程,但进程是操作系统创建的,而Java程序是不能直接调用系统功能的。但Java可以去调用C或C++写好的程序去创建进程从而实现多线程程序。

在Java中要想实现多线程操作有两种方式,一种是继承Thread类,另一种是实现Runnable接口。接下来针对这两种创建多线程的方式分别进行讲解。

实现多线程1: 继承Thread类#

Thread类概述

Thread类是在java.lang包中定义的类

JavaSE规范中规定,一个类只要继承了Thread类,此类就是多线程的子类。

在Thread子类中,必须重写该类的run()方法,此方法为线程的主体。

通过继承Thread类创建线程

接下来通过案例演示<通过继承Thread类的方式实现多线程>

下面创建线程,并测试主线程和创建的新线程(子线程)交替执行的效果

代码实现如下:

java
package thread;
​
/**
* @author 老安
* @data 2022/6/21 20:18
* 多线程
* 多线程可以并发执行多个任务
* 线程的第一种创建方式:
* 1:创建一个线程类,继承Thread类
* 2:在线程类中重写run方法
* 3:在run方法中写线程要执行的任务
* 4:实例化线程类对象
* 5:线程类对象调用方法start()启动线程
* 优点:结构简单
* 缺点:由于java中是单继承,此种方法已经继承了Thread,就无法再继承别的类了,
* 对于今后的实际开发造成很多不便
*/
public class ThreadDemo1 {
   public static void main(String[] args) {
       MyThread1 t1 = new MyThread1();
       MyThread2 t2 = new MyThread2();
       /*
        * 注意:启动线程不能调用run方法,因为run方法就是普通一个方法,
        * 必须调用start方法,调用start方法后,线程便会纳入线程调度器,
        * 一旦它被分到CPU时间片,就会开始自动执行线程中的run方法
        */
       t1.start();
       t2.start();
  }
}
//Thread 线程的超类
class MyThread1 extends Thread{
   //run方法是Thread类中定义的
   @Override
   public void run() {
       for(int i=0;i<1000;i++){
           System.out.println("你是谁啊?");
      }
  }
}
class MyThread2 extends Thread{
   //run方法是Thread类中定义的
   @Override
   public void run() {
       for (int i = 0; i < 1000; i++) {
           System.out.println("开门,我是查水表的!");
      }
  }
}

从上面的运行结果可以看出,main方法(主线程)和run方法(子线程)中的两个for循环中的输出语句交替执行了,说明通过集成Thread类实现了多线程。

(如果没有测试出主线程和子线程交替执行的效果,可以多测试几次!)

实现多线程2: 实现Runnable接口#

Runnable接口概述

通过继承Thread类实现了多线程,但是这种方式有一定的局限性。因为Java中只支持单继承,一个类一旦继承了某个父类就无法再继承Thread类,例如猫类Cat继承了动物类Animal,就无法通过继承Thread类实现多线程。

为了克服这种弊端,在Thread类中提供了两个构造方法:

public Thread(Runnable target)

public Thread(Runnable target,String name)

这两个构造方法都可以接收Runnable的子类实例对象,这样创建的线程将调用实现了Runnable接口类中的run()方法作为运行代码,而不需要调用Thread类的run()方法,所以就可以依靠Runnable接口的实现类启动多线程。

通过实现Runnable接口实现多线程

接下来通过案例演示<通过实现Runnable接口的方式实现多线程>

下面创建线程,并测试主线程和创建的新线程(子线程)交替执行的效果

代码实现如下:

java
package thread;
​
/**
* @author 老安
* @data 2022/6/21 20:53
* 第二种创建线程方式:
* 1:创建一个类,实现Runnable接口
* 2:重写Runnable中的run方法
* 3:run方法中写线程要执行的任务
* 4:实例化线程任务对象
* 5:实例化线程对象,并将任务对象作为参数传入
* 6:线程对象调用start方法启动线程
*/
public class ThreadDemo2 {
   public static void main(String[] args) {
       //实例化线程要执行的任务对象
       MyRunnable1 r1 = new MyRunnable1();
       MyRunnable2 r2 = new MyRunnable2();
       //实例化线程对象,并将任务对象传入其中
       Thread t1 = new Thread(r1);
       Thread t2 = new Thread(r2);
       //启动线程
       t1.start();
       t2.start();
  }
}
//Runnable不是线程,只是用来承载线程执行的内容的容器而已
class MyRunnable1 implements Runnable{
   @Override
   public void run() {
       for (int i = 0; i < 1000; i++) {
           System.out.println("hello~大姐姐~~");
      }
  }
}
class MyRunnable2 implements Runnable{
   @Override
   public void run() {
       for (int i = 0; i < 1000; i++) {
           System.out.println("来了~老六~~");
      }
  }
}

从上面的运行结果可以看出,main方法(主线程)和run方法(子线程)中的两个for循环中的输出语句交替执行了,说明实现Runnable接口同样也实现了多线程。

java
package thread;
​
/**
* @author 老安
* @data 2022/6/21 21:05
* 使用匿名内部类创建线程的方式
*/
public class ThreadDemo3 {
   public static void main(String[] args) {
       //直接继承Thread类重写run方法的形式
       Thread t1 = new Thread() {
           @Override
           public void run() {
               for (int i = 0; i < 1000; i++) {
                   System.out.println("who are you~~");
              }
          }
      };
       t1.start();
       //实现Runnable接口重写run方法的形式
//       Runnable r2 = new Runnable() {
//           @Override
//           public void run() {
//               for (int i = 0; i < 1000; i++) {
//                   System.out.println("i'm 老六~");
//               }
//           }
//       };
       Runnable r1 = () -> {
           for (int i = 0; i < 1000; i++) {
               System.out.println("i'm 老六~");
          }
      };
       Thread t2 = new Thread(r1);
       t2.start();
  }
}

Thread的常用方法和总结#

CurrentThreadDemo

java
package thread;
​
/**
* @author 老安
* @data 2022/6/21 21:21
* java中所有的代码都是靠线程运行的,main方法也需要由线程执行,
* JVM启动后,会创建一个线程,专门执行main方法,这个线程的名字,
* 叫做main,因此我们通常称这条线程叫做主线程.
* 但是主线程与我们创建的线程并无区别
* Thread类中提供了一个静态方法:
* static Thread currentThread()
* 该方法可以返回运行这个方法的线程
*/
public class CurrentThreadDemo {
   public static void main(String[] args) {
       Thread main = Thread.currentThread();
       doSome();
       //主线程:Thread[main,5,main]
       // 第一个main:线程名 5:优先级 第二个main:线程组
       System.out.println("主线程:"+main);
       new Thread("无敌霸王鸡"){
           @Override
           public void run() {
               Thread t = Thread.currentThread();
               System.out.println(t);
               doSome();
          }
      }.start();
  }
   public static void doSome(){
       Thread t = Thread.currentThread();
       System.out.println("运行doSome方法的线程:"+t);
  }
}

ThreadInfoDemo

java
package thread;
​
/**
* @author 老安
* @data 2022/6/23 19:37
* 获取线程相关的一组方法
*/
public class ThreadInfoDemo {
   public static void main(String[] args) {
       Thread main = Thread.currentThread();//获取到主线程
       String name = main.getName();//获取线程名
       System.out.println("名字:"+name);
       long id = main.getId();//获取线程的唯一标识(类似于人的身份证号)
       System.out.println("id:"+id);
       int priority = main.getPriority();//获取线程的优先级
       System.out.println("优先级:"+priority);
​
       boolean alive = main.isAlive();//线程是否还活着
       boolean daemon = main.isDaemon();//线程是否为守护线程
       boolean interrupted = main.isInterrupted();//线程是否被中断了
       System.out.println("是否活着:"+alive);
       System.out.println("是否为守护线程:"+daemon);
       System.out.println("是否被中断:"+interrupted);
  }
}

PriorityDemo

java
package thread;
​
/**
* @author 老安
* @data 2022/6/23 19:46
* 线程的优先级
* 线程有10个优先级,分别对应整数1-10,其中1是最低的优先级,10为最高级的优先级,5是默认值
* 线程start执行后,会被纳入到线程调度器中,统一管理,此时线程只能被动等待被分配时间片,线程不能主动的索取时间片,调度器会尽可能的均匀的分配时间片
* 但是优先级在多核心的前提下,是不作数了
*/
public class PriorityDemo {
   public static void main(String[] args) {
       Thread min = new Thread(){
           public void run() {
               for (int i = 0; i < 10000; i++) {
                   System.out.println("皇帝来找min啦");
              }
          }
      };
       Thread norm = new Thread(){
           public void run() {
               for (int i = 0; i < 10000; i++) {
                   System.out.println("皇帝来找norm啦");
              }
          }
      };
       Thread max = new Thread(){
           public void run() {
               for (int i = 0; i < 10000; i++) {
                   System.out.println("皇帝来找max啦");
              }
          }
      };
       //min.setPriority(1);
       min.setPriority(Thread.MIN_PRIORITY);
       max.setPriority(10);
       min.start();
       norm.start();
       max.start();
  }
}

进程#

什么是进程

进程是操作系统中运行得到一个任务(一个应用程序运行在一个进程中).

进程(process)是一块包含了某些资源的内存区域.操作同利用进程把它的工作划分为一些功能单元.

进程中所包含的一个或者多个执行单元称为线程(thread).进程拥有一个私有的虚拟地址空间,该空间仅能被他所包含的线程访问

线程只能归属于一个进程并且他只能访问该进程所拥有的资源.当操作系统创建一个进程后,该进程会自动申请一个主线程或者首要线程的线程

线程状态#

概述

image
image

  1. 新建状态(New):当一个线程对象被创建后,线程就处于新建状态。在新建状态中的线程对象从严格意义上看还只是一个普通的对象,还不是一个独立的线程,不会被线程调度程序调度。新建状态是线程生命周期的第一个状态。

例如: Thread t = new MyThread();

  1. 就绪状态(Runnable):处于新建状态中的线程被调用start()方法就会进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,但并不是说执行了start()方法线程就会立即执行;

另外,在等待/阻塞状态中的线程,被解除等待和阻塞后将不直接进入运行状态,而是首先进入就绪状态

  1. 运行状态(Running):处于就绪状态中的线程一旦被系统选中,使线程获取了 CPU 时间,就会进入运行状态。 线程在运行状态下随时都可能被调度程序调度回就绪状态。在运行状态下还可以让线程进入到等待/阻塞状态。 在通常的单核CPU中,在同一时刻只有一个线程处于运行状态。在多核的CPU中,就可能两个线程或更多的线程同时处于运行状态,这也是多核CPU运行速度快的原因。

注:就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,必须先处于就绪状态中;

  1. 阻塞状态(Blocked):根据阻塞产生的原因不同,阻塞状态又可以分为三种 a)等待阻塞:运行状态中的线程执行wait()方法,使当前线程进入到等待阻塞状态; b)锁阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程所占用),线程会进入同步阻塞状态; c)其他阻塞:通过调用线程的sleep(),suspend(), join(), 或发出了I/O请求时等,线程会进入到阻塞状态。当sleep()睡眠结束、调用resume(),?join()等待的线程终止或者超时、或I/O处理完毕时,线程重新转入就绪状态。

  2. 死亡状态(Dead):当线程中的run方法执行结束后,或者程序发生异常终止运行后,线程会进入死亡状态。处于死亡状态的线程不能再使用 start 方法启动线程。

SleepDemo

java
package thread;
​
import javafx.scene.transform.Scale;
​
import java.util.Scanner;
​
/**
* @author 老安
* @data 2022/6/23 20:50
* 线程提供了一个静态方法:
* static void sleep(long ms)
* 当一个线程调用sleep后,会进入阻塞状态指定的毫秒,超时后,会进入到Runnable状态,再次等待获取CPU的使用权,才能继续运行
*/
public class SleepDemo {
   public static void main(String[] args) {
       System.out.println("程序开始了!");
       /*
        * 倒计时程序
        * 程序启动后,输入一个数字,然后从该数字开始每秒递减,
        * 到0的时候输出时间到!
        * */
       Scanner scanner = new Scanner(System.in);
       System.out.println("请输入一个数字:");
       try {
           for (int num = scanner.nextInt(); num > 0; num--) {
               System.out.println(num);
               Thread.sleep(1000);
          }
      } catch (InterruptedException e) {
           e.printStackTrace();
      }
​
       System.out.println("程序结束了!");
  }
}

SleepDemo2

java
package thread;
​
/**
* @author 老安
* @data 2022/6/23 21:09
* sleep方法要求必须处理中断异常
* 当一个线程调用sleep方法处于睡眠阻塞的过程中,此时该线程的interrupt()方法
* 被调用时,会被立即中断睡眠阻塞,并抛出该异常
*/
public class SleepDemo2 {
   public static void main(String[] args) {
       Thread lin = new Thread(){
           @Override
           public void run() {
               System.out.println("林:刚美完容~睡一会吧~~");
               try {
                   Thread.sleep(500000000);
                   System.out.println("林:睡醒了!");
              } catch (InterruptedException e) {
                   System.out.println("林:干嘛呢!干嘛呢!都破了相了!");
              }
​
          }
      };
       Thread huang = new Thread(){
           @Override
           public void run() {
               System.out.println("黄:大锤80,小锤40,开始砸墙!");
               for (int i = 0; i < 5; i++) {
                   System.out.println("黄:80!");
                   try {
                       Thread.sleep(1000);
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
              }
               System.out.println("咣当!");
               System.out.println("黄:大哥!搞定!");
               lin.interrupt();//当huang线程执行到这里时,会让lin线程中断睡眠阻塞
          }
      };
       lin.start();
       huang.start();
  }
}

DaemonThreadDemo

java
package thread;
​
/**
* @author 老安
* @data 2022/6/23 21:25
* 守护线程
* java中将线程分为两类:用户线程和守护线程.也称为前台线程和后台线程.
* 守护线程和用户线程创建和使用上并无区别,但是最主要的区别:
* 当进程结束(一个java进程中所有的用户线程结束),
* 此时会将所有的守护线程全部杀死
* 守护线程是通过普通的用户线程通过调用setDaemon(true)设置而转变的
*/
public class DaemonThreadDemo {
   public static void main(String[] args) {
       Thread rose = new Thread(){//用户线程
           @Override
           public void run() {
               for (int i = 0; i < 5; i++) {
                   System.out.println("rose:let me go!");
                   try {
                       Thread.sleep(1000);
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
              }
               System.out.println("rose:aaaaaaaaaa~~~");
               System.out.println("扑通!!");
          }
      };
       Thread jack = new Thread(){
           @Override
           public void run() {
               while (true){
                   System.out.println("jack:you jump! i jump!");
                   try {
                       Thread.sleep(1000);
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
              }
          }
      };
       rose.start();
       jack.setDaemon(true);//将jack从用户线程设置为守护线程
       jack.start();
       while (true);
  }
}

线程的同步和异步#

JoinDemo

java
package thread;
​
/**
* @author 老安
* @data 2022/6/23 21:48
* 异步:线程各自执行各自的(多线程是并发运行的,本身就是异步的)
* 同步:多个线程执行是存在了先后顺序的
* 线程提供了一个方法:join,可以协调线程的同步运行
*/
public class JoinDemo {
   static boolean isFinish = false;//表示图片是否下载完毕
   public static void main(String[] args) {
       Thread download = new Thread() {
           @Override
           public void run() {
               System.out.println("down:开始下载图片...");
               for (int i = 0; i <= 100; i++) {
                   System.out.println("down:" + i + "%");
                   try {
                       Thread.sleep(50);
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
              }
               System.out.println("down:图片下载完毕!!!");
               isFinish = true; //true表示图片下载完毕
          }
      };
       Thread show = new Thread(){
           @Override
           public void run() {
               System.out.println("show:开始显示文字...");
               try {
                   Thread.sleep(2000);
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
               System.out.println("show:显示文字完毕!!!");
               //将show线程阻塞,直到download线程执行完毕(图片下载完毕)
               try {
                   /*
                    * 当show线程调用download.join()后便会进入阻塞状态.
                    * 直到download线程执行完毕才会解除阻塞
                    * join 参加
                    */
                   download.join();
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
               System.out.println("show:开始显示图片...");
               if (!isFinish){//if(true){} !isFinish=true isFinish=false
                   throw new RuntimeException("图片加载失败!!!");
              }
               System.out.println("show:图片显示完毕!!!");
          }
      };
       download.start();
       show.start();
  }
}

同步锁#

同步方法

同步方法概述

除了可以将需要的代码设置成同步代码块以外,也可以使用synchronized关键字将一个方法修饰成同步方法,它能实现和同步代码块同样的功能。

具体语法格式如下:

java
权限修饰符 synchronized 返回值类型/void 方法名([参数1,...]){
需要同步的代码;
}

被synchronized修饰的方法在某一时刻只允许一个线程访问,访问该方法的其他线程都会发生阻塞,直到当前线程访问完毕后,其他线程才有机会执行该方法。

需要注意的是,同步方法的锁是当前调用该方法的对象,也就是this指向的对象。

同步方法的使用

下面使用同步方法解决上面的多线程售票程序中的线程安全问题

需要注意的是:

  1. 将有可能发生线程安全问题的方法使用synchronized修饰,同一时间只允许一个线程进入同步方法中

  2. synchronized方法的锁对象是当前调用该方法的对象,也就是this指向的对象。

如果当前方法是非静态方法,this表示的是调用当前方法的对象

如果当前方法的静态方法,this表示的是当前类。

示例1: SyncDemo1

java
package thread;
​
/**
* 线程并发安全问题
* 当多个线程并发操作同一个临界资源,由于线程切换实际不确定,导致操作顺序出现混乱而引起的各种逻辑错误
* 临界资源:操作该资源的完整过程同一时刻只能由单线程执行
*/
public class SyncDemo1 {
   public static void main(String[] args) {
       Table table = new Table();
       Thread t1 = new Thread("小红"){
           @Override
           public void run() {
               while (true){
                   int bean = table.getBean();
                   Thread.yield();
                   System.out.println(getName()+"抢了一颗豆子,还剩:"+bean);
              }
          }
      };
       Thread t2 = new Thread("小蓝"){
           @Override
           public void run() {
               while (true){
                   int bean = table.getBean();
                   Thread.yield();
                   System.out.println(getName()+"抢了一颗豆子,还剩:"+bean);
              }
          }
      };
       t1.start();
       t2.start();
  }
}
class Table{
   private int beans = 20;//桌子上有20个豆子
​
   /*
    * 当一个方法使用关键字 synchronized后,该方法成为同步方法:
    * 多个线程不能同时执行这个方法,变相的排队了
    * 将多线程并发操作改为同步有先后顺序的排队执行可以有效的解决并发安全问题
    */
   public synchronized int getBean(){//每次调用该方法,可以取桌子上的一颗豆子
       if (beans <= 0){
           throw new RuntimeException("没有豆子了!!!");
      }
       Thread.yield();//让出时间片
       return beans--;
  }
}

同步代码块#

同步代码块概述

同步是指多个操作在同一个时间段内只能有一个线程进行,其他线程要等待此线程完成之后才可以继续执行。

Java为线程的同步操作提供了synchronized关键字,使用该关键字修饰的代码块被称为同步代码块。

其语法格式如下:

java
synchronized( 同步对象 ){
需要同步的代码;
}

注意: 在使用同步代码块时必须指定一个需要同步的对象,也称为锁对象,这里的锁对象可以是任意对象。但多个线程必须使用同一个锁对象。

同步代码块的使用

下面使用同步代码块解决上面的多线程售票程序中的线程安全问题

需要注意的是:

  1. 将有可能发生线程安全问题的代码包含在同步代码块中,同一时间只允许一个线程进入同步代码块中

  2. synchronized代码块中的锁对象可以是任意对象,但必须只能是一个锁。

若使用this作为锁对象,需保证多个线程执行时,this指向的是同一个对象

**示例1: **

java
package thread;
​
/**
* 同步块的应用
* 有效的缩小同步范围可以在保证并发安全问题的前提下尽可能的提高并发效率
* 语法:
* synchronized(同步监视器对象){
*     需要多个线程同步执行的代码片段
* }
*/
public class SyncDemo2 {
   public static void main(String[] args) {
       Shop shop1 = new Shop();
       Shop shop2 = new Shop();
       Thread t1 = new Thread("康荐文"){
           public void run() {
                shop1.buy();
          }
      };
       Thread t2 = new Thread("薛亚杰"){
           public void run() {
               shop2.buy();
          }
      };
       t1.start();
       t2.start();
  }
}
class Shop{
   //public synchronized void buy(){//买一件衣服,一般需要10s
   public void buy(){
       Thread t = Thread.currentThread();//获取运行buy方法的线程
       try {
           System.out.println(t.getName()+":正在挑衣服...");
           Thread.sleep(5000);
           /*
            * 同步块在使用时,需要在"()"中指定同步监视器对象,该对象可以是任何引用类型的实例.
            * 只要保证多个需要同步执行该代码块的线程看到的这个对象是"同一个"即可.
            * 实际开发中课结合具体情况选取
            */
           synchronized (this){
               System.out.println(t.getName()+":正在试衣服...");
               Thread.sleep(5000);
          }
           System.out.println(t.getName()+":正在结账离开...");
      } catch (InterruptedException e) {
      }
  }
}

静态同步方法#

示例1: SyncDemo3

java
package thread;
​
/**
* 静态方法锁
* 如果我们在静态方法上使用synchronized,那么该方法一定是具有同步效果
*/
public class SyncDemo3 {
   public static void main(String[] args) {
       Boo b1 = new Boo();
       Boo b2 = new Boo();
       Thread t1 = new Thread(){
           @Override
           public void run() {
               b1.doSome();
          }
      };
       Thread t2 = new Thread(){
           @Override
           public void run() {
               b2.doSome();
          }
      };
       t1.start();
       t2.start();
  }
}
class Boo {
   /**
    * 静态方法锁对象指的是当前类的类对象
    * 一个类的Class的实例全局唯一
    */
   //public synchronized static void doSome(){
   public static void doSome(){
       synchronized (Boo.class){
           Thread t = Thread.currentThread();
           System.out.println(t.getName()+":正在执行doSome方法...");
           try {
               Thread.sleep(5000);
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
           System.out.println(t.getName()+":执行doSome方法完毕!!!");
      }
  }
}

互斥锁#

示例

java
package thread;
​
/**
* 互斥锁
* 当使用多个synchronized锁定多个代码片段,并且指定的锁对象相同时,那么这些代码片段之间就是互斥的,多个线程不能同时访问他们
*/
public class SyncDemo4 {
   public static void main(String[] args) {
       Foo foo = new Foo();
       Thread t1 = new Thread(){
           @Override
           public void run() {
               foo.methodA();
          }
      };
       Thread t2 = new Thread(){
           @Override
           public void run() {
               foo.methodB();
          }
      };
       t1.start();
       t2.start();
  }
}
class Foo {
   public synchronized void methodA(){
       Thread t = Thread.currentThread();
       System.out.println(t.getName()+":正在执行A方法...");
       try {
           Thread.sleep(5000);
      } catch (InterruptedException e) {
           e.printStackTrace();
      }
       System.out.println(t.getName()+":执行A方法完毕...");
  }
   public synchronized void methodB(){
       Thread t = Thread.currentThread();
       System.out.println(t.getName()+":正在执行B方法...");
       try {
           Thread.sleep(5000);
      } catch (InterruptedException e) {
           e.printStackTrace();
      }
       System.out.println(t.getName()+":执行B方法完毕...");
  }
}

死锁#

示例

java
package thread;
​
/**
* 死锁
* 当多个线程都各自持有一个锁的同时,还等待对方先释放锁,就会形成一种僵持状态,这个就是死锁
*/
public class DeadLockDemo {
   static Object chopsticks = new Object();//筷子
   static Object spoon = new Object();//勺 调羹
   public static void main(String[] args) {
       Thread bf = new Thread() {
           @Override
           public void run() {
               try {//crtl+alt+L快速整理代码格式
                   System.out.println("北方人准备吃饭...");
                   synchronized (chopsticks) {//抢筷子,不释放筷子,别的线程拿不到筷子
                       System.out.println("北方人拿筷子,开始吃饭");
                       Thread.sleep(5000);
                       System.out.println("北方人吃完了饭,去拿勺");
                       synchronized (spoon){//抢勺
                           System.out.println("北方人拿勺,开始喝汤");
                           Thread.sleep(5000);
                           System.out.println("北方人喝完了汤");
                      }
                       System.out.println("北方人放下勺");
                  }
                   System.out.println("北方人放下筷子,吃饭完毕!");
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
      };
       Thread nf = new Thread() {
           @Override
           public void run() {
               try {//crtl+alt+L快速整理代码格式
                   System.out.println("南方人准备吃饭...");
                   synchronized (spoon) {//抢勺
                       System.out.println("南方人拿勺,开始喝汤");
                       Thread.sleep(5000);
                       System.out.println("南方人喝完了汤,去拿筷子");
                       synchronized (chopsticks){//抢筷子
                           System.out.println("南方人拿起筷子,开始吃饭");
                           Thread.sleep(5000);
                           System.out.println("南方人吃完了饭");
                      }
                       System.out.println("南方人放下筷子");
                  }
                   System.out.println("南方人放下勺,吃饭完毕!");
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
      };
       nf.start();
       bf.start();
  }
}

DeadLockDemo1

java
package thread;
​
/**
* 死锁
* 当多个线程都各自持有一个锁的同时,还等待对方先释放锁,就会形成一种僵持状态,这个就是死锁
*/
public class DeadLockDemo1 {
   static Object chopsticks = new Object();//筷子
   static Object spoon = new Object();//勺 调羹
​
   public static void main(String[] args) {
       Thread bf = new Thread() {
           @Override
           public void run() {
               try {//crtl+alt+L快速整理代码格式
                   System.out.println("北方人准备吃饭...");
                   synchronized (chopsticks) {//抢筷子,不释放筷子,别的线程拿不到筷子
                       System.out.println("北方人拿筷子,开始吃饭");
                       Thread.sleep(5000);
                       System.out.println("北方人吃完了饭");
                  }
                   System.out.println("北方人放下筷子,去拿勺");
                   synchronized (spoon) {//抢勺
                       System.out.println("北方人拿勺,开始喝汤");
                       Thread.sleep(5000);
                       System.out.println("北方人喝完了汤");
                  }
                   System.out.println("北方人放下勺");
                   System.out.println("吃饭完毕!");
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
      };
       Thread nf = new Thread() {
           @Override
           public void run() {
               try {//crtl+alt+L快速整理代码格式
                   System.out.println("南方人准备吃饭...");
                   synchronized (spoon) {//抢勺
                       System.out.println("南方人拿勺,开始喝汤");
                       Thread.sleep(5000);
                       System.out.println("南方人喝完了汤");
                  }
                   System.out.println("南方人放下勺,去拿筷子");
                   synchronized (chopsticks) {//抢筷子
                       System.out.println("南方人拿起筷子,开始吃饭");
                       Thread.sleep(5000);
                       System.out.println("南方人吃完了饭");
                  }
                   System.out.println("南方人放下筷子");
​
                   System.out.println("吃饭完毕!");
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
      };
       nf.start();
       bf.start();
  }
}
线程
https://blog.fileoz.com/posts/java-thread-basics/
作者
MIAOWU
发布于
2026-09-19
许可协议
CC BY-NC-SA 4.0

评论区

动作模组
等待模型加载…
看板娘
公告
公告大版本更新

一口气全面统一博客样式,移除部分冗余导航页面,更专注内容展示。

公告稳定性修复一批

统一Swup生命周期(BUG更少了、牺牲了首屏部分性能)、升级astro 7(构建速度翻倍)、文章封面图片加载(更流畅)、更换音乐播放器 API(更稳定)等多个问题,站点更稳了。

公告互换友链

欢迎各位大佬互换友链,要求内容原创、稳定更新。申请前请先看友链页的说明,期待和你交换链接。

查看详情
公告关于我的介绍

欢迎来到我的博客,我是深耕java、python和agent技术开发。热爱技术、持续学习,欢迎同好交流探讨。

查看详情
音乐
封面

音乐

暂未播放

0:00
0:00
暂无歌词

日历

正在加载日历...

--

    最近节日

    正在加载日历...
    ----

    最近生日/纪念日

    正在加载日历...
    ----
    距月底--
    距年底--

    隐私政策

    更新日期: 2026 年 7 月 15 日
    生效日期: 2026 年 7 月 15 日

    适用范围#

    本政策适用于 MiaoWu 的博客(以下简称“本站”)。本站是个人博客,用于发布和分享内容;不提供账户注册、支付、定位或广告投放服务。访问本站、发表文章评论或在留言板留言前,请阅读本政策。

    信息收集与使用#

    本站只在提供内容、评论和留言功能,以及维护站点安全所需的范围内处理信息。

    • 访问与统计信息:访问页面时,统计服务可能处理访问时间、页面地址、来源页、浏览器和设备相关信息,用于了解内容访问情况、排查故障和改进站点。
    • 评论信息:使用文章评论功能时,Waline 可能处理您主动提交的昵称、邮箱、站点链接和评论内容;还可能处理 IP 地址等必要信息,用于防止垃圾评论、滥用和维护服务安全。评论内容、昵称和站点链接(如填写)可能公开展示在文章下方;邮箱不会公开展示。
    • 留言信息:留言板使用 Waline /guestbook/ 频道。Waline 可能处理您主动提交的昵称、可选邮箱、站点链接、留言内容和图片,以及浏览器、操作系统、IP 地址等必要的反滥用信息。默认情况下,留言图片以内嵌数据随留言提交;如站点维护者配置了远程图片上传接口,图片会先发送至该接口并在留言中保存返回的图片地址。留言内容、昵称、图片和站点链接(如填写)可能公开展示;邮箱和 IP 地址不会在留言板公开展示。

    请不要在评论或留言中提交身份证件、银行卡、住址、密码或其他不必要的敏感个人信息。

    第三方服务#

    为实现本站功能,以下第三方会在各自服务范围内处理相关数据:

    • Umami:用于匿名化的网站访问统计和出站链接点击统计,帮助我了解本站的使用情况。
    • Waline:用于文章评论、留言板及访问量统计。服务会按照其自身规则处理您在评论或留言时提交的信息及必要的反滥用信息。
    • Cloudflare:可为本站提供静态资源分发和域名基础设施。
    • unpkg:用于加载 Waline 的前端脚本、样式和表情资源;请求这些资源时,您的浏览器会与该服务建立连接。

    第三方服务可能有独立的隐私政策和数据保存规则。请在使用相关功能前查阅其规则;本站无法控制其独立的数据处理活动。

    本站主要使用浏览器本地存储(Local Storage 或 Session Storage)保存使用偏好,例如主题颜色、明暗模式、文章列表视图和音乐播放设置。留言板会在本地保存匿名资料、未发送草稿和登录状态,以便恢复输入与会话;管理员登录状态仅保存在当前会话。

    本站不主动设置用于广告定向的第一方 Cookie。评论、统计或资源服务可能按照其自身规则使用 Cookie 或类似技术。您可以通过浏览器设置查看、删除或限制 Cookie 和本地存储;清除后,部分偏好或互动状态可能会恢复为默认值,评论功能也可能受到影响。

    信息公开、保存与安全#

    评论和留言属于公开互动内容,提交后可能被搜索引擎收录、被他人引用或在缓存中短暂保留。请谨慎决定发布内容。除非您提出删除请求、内容违反规则或法律法规另有要求,公开内容会持续保留以维持讨论上下文。

    本站会采取合理措施保护数据安全,包括使用 HTTPS、输入校验、内容转义和访问频率限制。但互联网传输和第三方服务均无法保证绝对安全,请理解并自行承担公开发布信息的相应风险。

    你的权利#

    你可以通过 996491835@qq.com 联系我,申请查询、更正或删除由本站直接保存的评论、留言或相关公开内容。为保护他人权益,请在请求中提供足以定位内容的信息,并说明你与该内容的关系;必要时可能需要进行合理核验。

    对于由 Waline、Umami、Cloudflare 或 unpkg 独立处理的数据,你也可以直接向对应服务提供方行使相关权利。删除公开评论或留言后,第三方缓存、搜索引擎索引或他人转载的副本可能无法立即同步删除。

    未成年人条款#

    未满 14 周岁的未成年人应在监护人同意和指导下使用本站的评论、留言等互动功能。监护人如发现未成年人未经同意提交了个人信息,可通过上述联系方式与我联系,我会在合理范围内协助处理。

    政策更新与联系#

    我可能因本站功能或适用规则变化更新本政策,更新后的版本将在本站公布并标明日期。继续使用相关功能即表示你已阅读并理解更新后的政策。

    如对本政策或数据处理有疑问,请联系 996491835@qq.com。

    用户协议

    更新日期: 2026 年 5 月 19 日
    生效日期: 2026 年 5 月 19 日

    适用范围#

    本协议适用于你访问 MiaoWu 的博客,以及使用文章评论、留言板等互动功能的行为。继续浏览本站或提交评论、留言,即表示你已阅读、理解并同意遵守本协议及本站的隐私政策。

    评论及留言规则#

    请在交流中保持友善、理性和尊重。你不得利用本站发布、传播或实施以下行为:

    • 发布任何违反中华人民共和国法律法规的内容。
    • 发布任何侵犯他人合法权益的内容,包括但不限于隐私、名誉、肖像、著作权、商标权和其他知识产权。
    • 恶意攻击、辱骂、骚扰、威胁、歧视其他用户或任何第三方。
    • 发布垃圾广告、恶意推广、刷屏、灌水,或与讨论主题明显无关的重复内容。
    • 利用本站进行网络诈骗、钓鱼、传播恶意软件,或发布可能危害网络和信息安全的内容。
    • 绕越或试图绕越本站的审核、限流、封禁等管理措施。
    • 冒充他人、伪造身份,或收集、公开他人的个人信息。

    内容与访问管理#

    你应对自己发布的评论和留言负责,并保证拥有发布该等内容所需的合法权利。论坛管理员有权在不另行通知的情况下删除违规内容、限制或封禁违规账号,或限制其继续使用本站互动功能。

    如发现涉嫌违法犯罪、严重侵权或危及本站安全的内容,本站可保留相关记录,并在法律法规要求或必要时向有关部门提供协助。对管理措施有疑问时,可通过文末联系方式说明情况;本站会结合实际情况处理,但不承诺恢复已删除内容或访问权限。

    知识产权与内容授权#

    本站原创文章、页面设计和其他受保护内容的权利归作者或权利人所有。未经授权,请勿复制、转载、镜像或用于商业用途;法律法规允许的合理使用除外。

    你发布评论或留言时,授予本站为展示、存储、备份、审核、删除和维护互动功能所必需的非独占、免费的使用许可。该许可不改变你对原创内容依法享有的权利。

    免责声明#

    本站内容仅用于个人记录、学习交流和一般信息参考,不构成任何专业意见、承诺或担保。你应结合自身情况独立判断,并对据此采取的行动负责。

    评论、留言和外部链接中的内容由其发布者或运营者负责,不代表本站立场。本站会在合理范围内处理明显违规内容,但不保证所有内容均及时发现,也不对第三方网站的可用性、内容、安全性或隐私实践承担责任。

    因网络故障、不可抗力、第三方服务异常、维护升级或超出合理控制范围的原因导致本站暂时无法访问、内容延迟或数据丢失的,本站会尽力恢复,但不承担由此产生的间接损失。

    未成年人条款#

    未满 14 周岁的未成年人应在监护人同意和指导下使用评论、留言等互动功能。监护人应协助未成年人理解本协议,并对其使用行为进行必要的引导。

    其他条款#

    我可以根据本站功能、管理需要或法律法规变化更新本协议,更新后的版本将在本站公布并标明日期。继续使用本站即视为接受更新后的协议。

    本协议的订立、执行和解释适用中华人民共和国法律。因本协议或使用本站产生争议时,双方应先友好协商;协商不成的,依法向有管辖权的人民法院解决。

    如对本协议或内容管理有疑问,请联系 996491835@qq.com。

    复制成功,转载请标注本文地址