Java 线程

1、创建线程类(方法一)

Java使用 java.lang.Thread 类代表线程,所有的线程对象都必须是 Thread 类或其子类的实例。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。Java 使用线程执行体来代表这段程序流。 Java 中通过继承 Thread 类来创建并启动多线程的步骤如下:

  1. 定义 Thread 类的子类,并重写该类的 run() 方法该 run() 方法的方法体就代表了线程需要完成的任务,因此把 run() 方法称为线程执行体。
  2. 创建 Thread 子类的实例,即创建了线程对象。
  3. 调用线程对象的 start() 方法来启动该线程。

2、线程同步问题

程序启动运行 main 时候,java 虚拟机启动一个进程,主线程 main 在 main() 调用时候被创建。随着调用 mt 的对象的 start 方法,另外一个新的线程也启动了,这样,整个应用就在多线程下运行。

多线程执行时,在栈内存中,其实每一个执行线程都有一片自己所属的栈内存空间。进行方法的压栈和弹栈。

当执行线程的任务结束了,线程自动在栈内存中释放了。但是当所有的执行线程都结束了,那么进程就结束了。

2.1、Thread类

2.1.1、构造方法

  • public Thread() :分配一个新的线程对象。
  • public Thread(String name) :分配一个指定名字的新的线程对象。
  • public Thread(Runnable target) :分配一个带有指定目标新的线程对象。
  • public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。

2.1.2、常用方法

  • public String getName() :获取当前线程名称。
  • public void start() :导致此线程开始执行; Java 虚拟机调用此线程的 run 方法。
  • public void run() :此线程要执行的任务在此处定义代码。
  • public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
  • public static Thread currentThread() :返回对当前正在执行的线程对象的引用。

2.2、创建线程方式二

采用 java.lang.Runnable 也是非常常见的一种,我们只需要重写 run 方法即可

步骤如下:

  1. 定义 Runnable 接口的实现类,并重写该接口的 run() 方法,该 run() 方法的方法体同样是该线程的线程执行体。
  2. 创建 Runnable 实现类的实例,并以此实例作为 Thread 的 target 来创建 Thread 对象,该 Thread 对象才是真正的线程对象。
  3. 调用线程对象的 start() 方法来启动线程。

通过实现 Runnable 接口,使得该类有了多线程类的特征。run() 方法是多线程程序的一个执行目标。所有的多线程代码都在 run方法里面。Thread 类实际上也是实现了 Runnable 接口的类。

在启动的多线程的时候,需要先通过 Thread 类的构造方法 Thread(Runnable target) 构造出对象,然后调用 Thread 对象的start() 方法来运行多线程代码。

实际上所有的多线程代码都是通过运行 Thread 的 start() 方法来运行的。因此,不管是继承 Thread 类还是实现 Runnable 接口来实现多线程,最终还是通过 Thread 的对象的 API 来控制线程的,熟悉 Thread 类的 API 是进行多线程编程的基础。

tips:

Runnable 对象仅仅作为 Thread 对象的 target,Runnable 实现类里包含的 run() 方法仅作为线程执行体。 而实际的线程对象依然是 Thread 实例,只是该 Thread 线程负责执行其 target 的 run() 方法。

2.3、Thread 和 Runnable 的区别

如果一个类继承 Thread,则不适合资源共享。但是如果实现了 Runable 接口的话,则很容易的实现资源共享

总结:

实现 Runnable 接口比继承 Thread 类所具有的优势:

  1. 适合多个相同的程序代码的线程去共享同一个资源。
  2. 可以避免 java 中的单继承的局限性。
  3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
  4. 线程池只能放入实现 Runable 或 Callable 类线程,不能直接放入继承 Thread 的类。

扩充:在 java 中,每次程序运行至少启动 2 个线程。一个是 main 线程,一个是垃圾收集线程。因为每当使用 java 命令执行一个类的时候,实际上都会启动一个 JVM,每一个 JVM 其实在就是在操作系统中启动了一个进程。

2.4、匿名内部类方式实现线程的创建

使用线程的内匿名内部类方式,可以方便的实现每个线程执行不同的线程任务操作。

使用匿名内部类的方式实现 Runnable 接口,重新 Runnable 接口中的 run 方法:

public class NoNameInnerClassThread {public static void main(String[] args) {// new Runnable(){// public void run(){// for (int i = 0; i < 20; i++) {// System.out.println("张宇:"+i);// }// }// }; //‐‐‐这个整体 相当于new MyRunnable()Runnable r = new Runnable(){public void run(){for (int i = 0; i < 20; i++) {System.out.println("张宇:"+i);}}};new Thread(r).start();for (int i = 0; i < 20; i++) {System.out.println("费玉清:"+i);}}
}

3、线程安全

3.1、线程同步

当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题。

要解决上述多线程并发访问一个资源的安全性问题:也就是解决重复票与不存在票问题,Java 中提供了**同步机制 (synchronized)**来解决。

为了保证每个线程都能正常执行原子操作,Java 引入了线程同步机制。

那么怎么去使用呢?有三种方式完成同步操作:

  1. 同步代码块。
  2. 同步方法。
  3. 锁机制。

3.2、同步代码块

  • 同步代码块synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。

格式:

synchronized(同步锁){需要同步操作的代码
}

同步锁:

对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁。

  • 锁对象 可以是任意类型。
  • 多个线程对象 要使用同一把锁。

注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着 (BLOCKED)。

3.3、同步方法

  • 同步方法:使用 synchronized 修饰的方法,就叫做同步方法,保证 A 线程执行该方法的时候,其他线程只能在方法外等着。

格式:

public synchronized void method(){可能会产生线程安全问题的代码
}

同步锁是谁?

对于非 static 方法,同步锁就是 this。

对于 static 方法,我们使用当前方法所在类的字节码对象(类名.class)。

3.4、Lock 锁

java.util.concurrent.locks.Lock 机制提供了比 synchronized 代码块和 synchronized 方法更广泛的锁定操作, 同步代码块/同步方法具有的功能 Lock 都有,除此之外更强大,更体现面向对象。

Lock 锁也称同步锁,加锁与释放锁方法化了,如下:

  • public void lock() :加同步锁。
  • public void unlock() :释放同步锁。

4、线程状态

4.1、概述

当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中, 有几种状态呢?在 API 中 java.lang.Thread.State 这个枚举中给出了六种线程状态

这里先列出各个线程状态发生的条件,下面将会对每种状态进行详细解析:

线程状态 导致状态发生条件
NEW(新建) 线程刚被创建,但是并未启动。还没调用start方法。
Runnable(可 运行) 线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操 作系统处理器。
Blocked(锁阻 塞) 当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状 态;当该线程持有锁时,该线程将变成Runnable状态。
Waiting(无限 等待) 一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个 状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。
Timed Waiting(计时 等待) 同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态 将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、 Object.wait。
Teminated(被 终止) 因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

我们不需要去研究这几种状态的实现原理,我们只需知道在做线程操作中存在这样的状态。那我们怎么去理解这几个状态呢,新建与被终止还是很容易理解的,我们就研究一下线程从Runnable(可运行)状态与非运行状态之间的转换问题。

4.2、 Timed Waiting(计时等待)

Timed Waiting 在 API 中的描述为:一个正在限时等待另一个线程执行一个(唤醒)动作的线程处于这一状态

为了减少线程执行太快,现象不明显等问题,我们在 run 方法中添加了 sleep 语句,这样就强制当前正在执行的线程休眠(暂停执行),以 “减慢线程”。

其实当我们调用了 sleep 方法之后,当前执行的线程就进入到 “休眠状态”,其实就是所谓的 Timed Waiting(计时等待)。

我们需要记住下面几点:

  1. 进入 TIMED_WAITING 状态的一种常见情形是调用的 sleep 方法,单独的线程也可以调用,不一定非要有协作关系。
  2. 为了让其他线程有机会执行,可以将 Thread.sleep() 的调用放线程 run() 之内。这样才能保证该线程执行过程中会睡眠。
  3. sleep 与锁无关,线程睡眠到期自动苏醒,并返回到Runnable(可运行)状态。

小提示:sleep() 中指定的时间是线程不会运行的最短时间。因此,sleep() 方法不能保证该线程睡眠到期后就开始立刻执行。

4.3、BLOCKED(锁阻塞)

Blocked 状态在 API 中的介绍为:一个正在阻塞等待一个监视器锁(锁对象)的线程处于这一状态

我们已经学完同步机制,那么这个状态是非常好理解的了。比如,线程 A 与线程 B 代码中使用同一锁,如果线程 A 获取到锁,线程 A 进入到 Runnable 状态,那么线程 B 就进入到Blocked 锁阻塞状态。

4.4、Waiting(无限等待)

Wating 状态在 API 中介绍为:一个正在无限期等待另一个线程执行一个特别的(唤醒)动作的线程处于这一状态。

一个调用了某个对象的 Object.wait 方法的线程会等待另一个线程调用此对象的 Object.notify() 方法或 Object.notifyAll() 方法。

其实 waiting 状态并不是一个线程的操作,它体现的是多个线程间的通信,可以理解为多个线程之间的协作关系, 多个线程会争取锁,同时相互之间又存在协作关系。就好比在公司里你和你的同事们,你们可能存在晋升时的竞争,但更多时候你们更多是一起合作以完成某些任务。

当多个线程协作时,比如 A,B 线程,如果 A 线程在Runnable(可运行)状态中调用了 wait() 方法那么 A 线程就进入了 Waiting(无限等待)状态,同时失去了同步锁。假如这个时候 B 线程获取到了同步锁,在运行状态中调用了 notify() 方法,那么就会将无限等待的 A 线程唤醒。注意是唤醒,如果获取到锁对象,那么 A 线程唤醒后就进入 Runnable(可运行)状态;如果没有获取锁对象,那么就进入到 Blocked(锁阻塞状态)。


5、等待唤醒机制

5.1、线程间通信

概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。

为什么要处理线程间通信:

多个线程并发执行时, 在默认情况下 CPU 是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们希望他们有规律的执行, 那么多线程之间需要一些协调通信,以此来帮我们达到多线程共同操作一份数据。

如何保证线程间通信有效利用资源:

多个线程在处理同一个资源,并且任务不同时,需要线程通信来帮助解决线程之间对同一个变量的使用或操作。 就是多个线程在操作同一份数据时, 避免对同一共享变量的争夺。也就是我们需要通过一定的手段使各个线程能有效的利用资源。而这种手段即—— 等待唤醒机制。

5.2、 等待唤醒机制

什么是等待唤醒机制

这是多个线程间的一种协作机制。谈到线程我们经常想到的是线程间的竞争(race),比如去争夺锁,但这并不是故事的全部,线程间也会有协作机制。就好比在公司里你和你的同事们,你们可能存在在晋升时的竞争,但更多时 候你们更多是一起合作以完成某些任务。

就是在一个线程进行了规定操作后,就进入等待状态(wait()), 等待其他线程执行完他们的指定代码过后再将其唤醒(notify());在有多个线程进行等待时, 如果需要,可以使用 notifyAll() 来唤醒所有的等待线程。 wait/notify 就是线程间的一种协作机制

等待唤醒中的方法

等待唤醒机制就是用于解决线程间通信的问题的,使用到的 3 个方法的含义如下:

  1. wait:线程不再活动,不再参与调度,进入 wait set 中,因此不会浪费 CPU 资源,也不会去竞争锁了,这时的线程状态即是 WAITING。它还要等着别的线程执行一个特别的动作,也即是 “通知(notify)” 在这个对象上等待的线程从 wait set 中释放出来,重新进入到调度队列(ready queue)中。
  2. notify:则选取所通知对象的 wait set 中的一个线程释放;例如,餐馆有空位置后,等候就餐最久的顾客最先入座。
  3. notifyAll:则释放所通知对象的 wait set 上的全部线程。

注意:

哪怕只通知了一个等待的线程,被通知线程也不能立即恢复执行,因为它当初中断的地方是在同步块内,而此刻它已经不持有锁,所以她需要再次尝试去获取锁(很可能面临其它线程的竞争),成功后才能在当初调用 wait 方法之后的地方恢复执行。

总结如下:

如果能获取锁,线程就从 WAITING 状态变成 RUNNABLE 状态; 否则,从 wait set 出来,又进入 entry set,线程就从 WAITING 状态又变成 BLOCKED 状态

调用 wait 和 notify 方法需要注意的细节:

  1. wait 方法与 notify 方法必须要由同一个锁对象调用。因为:对应的锁对象可以通过 notify 唤醒使用同一个锁对象调用的 wait方法后的线程。
  2. wait 方法与 notify 方法是属于 Object 类的方法的。因为:锁对象可以是任意对象,而任意对象的所属类都是继承了 Object类的。
  3. wait 方法与 notify 方法必须要在同步代码块或者是同步函数中使用。因为:必须要通过锁对象调用这 2 个方法。

6、线程池

6.1、线程池思想概述

我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:

如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。

那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?

在 Java 中可以通过线程池来达到这样的效果。今天我们就来详细讲解一下 Java 的线程池。

6.2、线程池概念

  • 线程池其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作, 无需反复创建线程而消耗过多资源。

由于线程池中有很多操作都是与优化资源相关的,我们在这里就不多赘述。我们通过一张图来了解线程池的工作原理:

合理利用线程池能够带来三个好处:

  1. 降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
  2. 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
  3. 提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约 1MB 内存,线程开的越多,消耗的内存也就越大,最后死机)。

6.3、线程池的使用

Java 里面线程池的顶级接口是 java.util.concurrent.Executor ,但是严格意义上讲 Executor 并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是 java.util.concurrent.ExecutorService

要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池不是较优的,因此在 java.util.concurrent.Executors 线程工厂类里面提供了一些静态工厂,生成一些常用的线程池。官方建议使用 Executors 工程类来创建线程池对象

Executors 类中有个创建线程池的方法如下:

  • public static ExecutorService newFixedThreadPool(int nThreads) :返回线程池对象。(创建的是有界线程池,也就是池中的线程个数可以指定最大数量)

获取到了一个线程池 ExecutorService 对象,那么怎么使用呢,在这里定义了一个使用线程池对象的方法如下:

  • public Future submit(Runnable task) :获取线程池中的某一个线程对象,并执行

    Future接口:用来记录线程任务执行完毕后产生的结果。线程池创建与使用。

使用线程池中线程对象的步骤:

  1. 创建线程池对象。
  2. 创建 Runnable 接口子类对象。(task)
  3. 提交 Runnable 接口子类对象。(take task)
  4. 关闭线程池(一般不做)。

Runnable 实现类代码:

public class MyRunnable implements Runnable{@Overridepublic void run() {System.out.println("I need a coach.");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("The coach is coming:" + Thread.currentThread().getName());System.out.println("The coach return back to the \"pools\"");}
}

线程池测试类:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class TestPools {public static void main(String[] args) {// 创建线程池对象ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象// 创建Runnable实例对象MyRunnable r = new MyRunnable();//自己创建线程对象的方式// Thread t = new Thread(r);// t.start(); ‐‐‐> 调用MyRunnable中的run()// 从线程池中获取线程对象,然后调用MyRunnable中的run()service.submit(r);// 再获取个线程对象,调用MyRunnable中的run()service.submit(r);service.submit(r);// 注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。// 将使用完的线程又归还到了线程池中// 关闭线程池//service.shutdown();}
}
I need a coach.
I need a coach.
The coach is coming:pool-1-thread-1
The coach return back to the "pools"
The coach is coming:pool-1-thread-2
The coach return back to the "pools"
I need a coach.
The coach is coming:pool-1-thread-2
The coach return back to the "pools"

7、消费者-生产者问题

  • 缓冲区类

    public class Suffer {private static int empty = 5;private static int full = 0;Object lock = new Object();public void produce(){synchronized (lock){while (Suffer.empty <= 0){try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName() + " :");System.out.println("    There are(is) " + Suffer.empty + " empty position(s) in suffer.");Suffer.full++;Suffer.empty--;System.out.println("    store a produce.");System.out.println("    now, there are(is) " + Suffer.full + " produce(s) in suffer.");System.out.println("-------------------------------------------------------------------");lock.notifyAll();}}public void consume(){synchronized (lock){while (Suffer.full <= 0){try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName() + " :");System.out.println("    There are(is) " + Suffer.full + " produce(s) in suffer.");Suffer.full--;Suffer.empty++;System.out.println("    fetch a produce.");System.out.println("    now, there are(is) " + Suffer.full + " produce(s) in suffer.");System.out.println("-------------------------------------------------------------------");lock.notifyAll();}}
    }
    
  • 生产者类

    public class Producer implements Runnable{private Suffer suffer;public Producer(Suffer suffer) {this.suffer = suffer;}@Overridepublic void run() {while (true){try {Thread.sleep(1000);suffer.produce();} catch (InterruptedException e) {e.printStackTrace();}}}
    }
    
  • 消费者类

    public class Customer implements Runnable{private Suffer suffer;public Customer() {}public Customer(Suffer suffer) {this.suffer = suffer;}@Overridepublic void run() {while (true) {try {Thread.sleep(1000);suffer.consume();} catch (InterruptedException e) {e.printStackTrace();}}}
    }
    
  • 测试类

    public class TestDemo3 {public static void main(String[] args) {Suffer suffer = new Suffer();Thread p1 = new Thread(new Producer(suffer), "Producer1");Thread p2 = new Thread(new Producer(suffer), "Producer2");Thread p3 = new Thread(new Producer(suffer), "Producer3");Thread c1 = new Thread(new Customer(suffer), "Customer1");Thread c2 = new Thread(new Customer(suffer), "Customer2");Thread c3 = new Thread(new Customer(suffer), "Customer3");c1.start();c2.start();c3.start();p1.start();p2.start();p3.start();}
    }
    
  • 运行

    Producer3 :There are(is) 5 empty position(s) in suffer.store a produce.now, there are(is) 1 produce(s) in suffer.
    -------------------------------------------------------------------
    Customer2 :There are(is) 1 produce(s) in suffer.fetch a produce.now, there are(is) 0 produce(s) in suffer.
    -------------------------------------------------------------------
    Producer2 :There are(is) 5 empty position(s) in suffer.store a produce.now, there are(is) 1 produce(s) in suffer.
    -------------------------------------------------------------------
    Producer1 :There are(is) 4 empty position(s) in suffer.store a produce.now, there are(is) 2 produce(s) in suffer.
    -------------------------------------------------------------------
    Customer3 :There are(is) 2 produce(s) in suffer.fetch a produce.now, there are(is) 1 produce(s) in suffer.
    -------------------------------------------------------------------
    Customer1 :There are(is) 1 produce(s) in suffer.fetch a produce.now, there are(is) 0 produce(s) in suffer.
    -------------------------------------------------------------------
    Producer3 :There are(is) 5 empty position(s) in suffer.store a produce.now, there are(is) 1 produce(s) in suffer.
    -------------------------------------------------------------------
    Customer1 :There are(is) 1 produce(s) in suffer.fetch a produce.now, there are(is) 0 produce(s) in suffer.
    -------------------------------------------------------------------
    Producer2 :There are(is) 5 empty position(s) in suffer.store a produce.now, there are(is) 1 produce(s) in suffer.
    -------------------------------------------------------------------
    Customer3 :There are(is) 1 produce(s) in suffer.fetch a produce.now, there are(is) 0 produce(s) in suffer.
    -------------------------------------------------------------------
    ...
    

8、多生产者和消费者问题

  • 盘子类

    public class Plate {private static int plate = 1;private static int apple = 0;private static int orange = 0;Object lock = new Object();public void mom(){synchronized (lock){while (Plate.plate == 0){try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("mom :");System.out.println("    mom prepares an \"apple\" and put the apple on the plate.");Plate.plate--;Plate.apple++;System.out.println("    now there is an \"apple\" on the plate.");lock.notifyAll();}}public void dad(){synchronized (lock){while (Plate.plate == 0){try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("dad :");System.out.println("    dad prepares an \"orange\" and put the orange on the plate.");Plate.plate--;Plate.orange++;System.out.println("    now there is an \"orange\" on the plate.");lock.notifyAll();}}public void daughter(){synchronized (lock){while (Plate.apple == 0){try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("daughter :");System.out.println("    daughter has taken the \"apple\".");Plate.plate++;Plate.apple--;System.out.println("    now the plate is empty.");System.out.println("---------------------------------------------------");lock.notifyAll();}}public void son(){synchronized (lock){while (Plate.orange == 0){try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("son :");System.out.println("    son has taken the \"orange\".");Plate.plate++;Plate.orange--;System.out.println("    now the plate is empty.");System.out.println("---------------------------------------------------");lock.notifyAll();}}}
    
  • 父亲类

    public class Dad implements Runnable{private Plate plate;public Dad(Plate plate) {this.plate = plate;}@Overridepublic void run() {while (true){try {Thread.sleep(1000);plate.dad();} catch (InterruptedException e) {e.printStackTrace();}}}
    }
    
  • 母亲类

    public class Mom implements Runnable{private Plate plate;public Mom(Plate plate) {this.plate = plate;}@Overridepublic void run() {while (true){try {Thread.sleep(1000);plate.mom();} catch (InterruptedException e) {e.printStackTrace();}}}
    }
    
  • 女儿类

    public class Daughter implements Runnable{private Plate plate;public Daughter(Plate plate) {this.plate = plate;}@Overridepublic void run() {while (true){try {Thread.sleep(1000);plate.daughter();} catch (InterruptedException e) {e.printStackTrace();}}}
    }
    
  • 儿子类

    public class Son implements Runnable{private Plate plate;public Son(Plate plate) {this.plate = plate;}@Overridepublic void run() {while (true){try {Thread.sleep(1000);plate.son();} catch (InterruptedException e) {e.printStackTrace();}}}
    }
    
  • 测试类

    public class TestMulti_CS {public static void main(String[] args) {Plate plate = new Plate();Thread mom = new Thread(new Mom(plate));Thread dad = new Thread(new Dad(plate));Thread daughter = new Thread(new Daughter(plate));Thread son = new Thread(new Son(plate));mom.start();dad.start();daughter.start();son.start();}
    }
    
  • 运行

    mom :mom prepares an "apple" and put the apple on the plate.now there is an "apple" on the plate.
    daughter :daughter has taken the "apple".now the plate is empty.
    ---------------------------------------------------
    dad :dad prepares an "orange" and put the orange on the plate.now there is an "orange" on the plate.
    son :son has taken the "orange".now the plate is empty.
    ---------------------------------------------------
    dad :dad prepares an "orange" and put the orange on the plate.now there is an "orange" on the plate.
    son :son has taken the "orange".now the plate is empty.
    ---------------------------------------------------
    mom :mom prepares an "apple" and put the apple on the plate.now there is an "apple" on the plate.
    daughter :daughter has taken the "apple".now the plate is empty.
    ---------------------------------------------------
    

9、吸烟者问题

  • 供应者类

    import java.util.Random;public class Producer implements Runnable{private static int offer1 = 0;  //烟草和纸的组合private static int offer2 = 0;  //烟草和胶水的组合private static int offer3 = 0; //纸和胶水的组合Object lock = new Object();@Overridepublic void run() {synchronized (lock) {while (true) {Random r = new Random();int random = r.nextInt() % 3;if (random == 0) {Producer.offer1++;System.out.println("Producer:");System.out.println("    I offered the \"tobacco and paper\".");lock.notifyAll();} else if (random == 1) {Producer.offer2++;System.out.println("Producer:");System.out.println("    I offered the \"tobacco and glue\".");lock.notifyAll();} else {Producer.offer3++;System.out.println("Producer:");System.out.println("    I offered the \"paper and glue\".");lock.notifyAll();}try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}public Producer() {}public void somker1(){ //need offer1synchronized (lock){while (true){if(Producer.offer1 == 1){System.out.println("somker1 :");System.out.println("    I need the \"tobacco and paper\".");Producer.offer1--;System.out.println("-------------------------------------------");lock.notifyAll();}try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}public void somker2(){  //need offer2synchronized (lock){while (true){if(Producer.offer2 == 1){System.out.println("somker2 :");System.out.println("    I need the \"tobacco and glue\".");Producer.offer2--;System.out.println("-------------------------------------------");lock.notifyAll();}try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}public void smoker3(){  //need offer3synchronized (lock){while (true){if(Producer.offer3 == 1){System.out.println("somker3 :");System.out.println("    I need the \"paper and glue\".");Producer.offer3--;System.out.println("-------------------------------------------");lock.notifyAll();}try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}}
    
  • 吸烟者 1 号类

    public class Smoker1 implements Runnable{private Producer producer;public Smoker1(Producer producer) {this.producer = producer;}@Overridepublic void run() {while (true){try {Thread.sleep(1000);producer.somker1();} catch (InterruptedException e) {e.printStackTrace();}}}
    }
    
  • 吸烟者 2 号类

    public class Smoker2 implements Runnable{private Producer producer;public Smoker2(Producer producer) {this.producer = producer;}@Overridepublic void run() {while (true){try {Thread.sleep(1000);producer.somker2();} catch (InterruptedException e) {e.printStackTrace();}}}
    }
    
  • 吸烟者 3 号类

    public class Smoker3 implements Runnable{private Producer producer;public Smoker3(Producer producer) {this.producer = producer;}@Overridepublic void run() {while (true){try {Thread.sleep(1000);producer.smoker3();} catch (InterruptedException e) {e.printStackTrace();}}}
    }
    
  • 测试类

    public class TestSmoker {public static void main(String[] args) {Producer prod = new Producer();Thread producer = new Thread(prod);Thread smoker1 = new Thread(new Smoker1(prod));Thread smoker2 = new Thread(new Smoker2(prod));Thread smoker3 = new Thread(new Smoker3(prod));producer.start();smoker1.start();smoker2.start();smoker3.start();}
    }
    
  • 运行

    Producer:I offered the "paper and glue".
    somker3 :I need the "paper and glue".
    -------------------------------------------
    Producer:I offered the "paper and glue".
    somker3 :I need the "paper and glue".
    -------------------------------------------
    Producer:I offered the "paper and glue".
    somker3 :I need the "paper and glue".
    -------------------------------------------
    Producer:I offered the "tobacco and paper".
    somker1 :I need the "tobacco and paper".
    -------------------------------------------
    Producer:I offered the "tobacco and glue".
    somker2 :I need the "tobacco and glue".
    -------------------------------------------
    Producer:I offered the "paper and glue".
    somker3 :I need the "paper and glue".
    -------------------------------------------
    Producer:I offered the "tobacco and paper".
    somker1 :I need the "tobacco and paper".
    -------------------------------------------
    Producer:I offered the "paper and glue".
    somker3 :I need the "paper and glue".
    -------------------------------------------
    Producer:I offered the "tobacco and paper".
    somker1 :I need the "tobacco and paper".
    -------------------------------------------
    Producer:I offered the "paper and glue".
    somker3 :I need the "paper and glue".
    -------------------------------------------
    Producer:I offered the "paper and glue".
    somker3 :I need the "paper and glue".
    -------------------------------------------
    Producer:I offered the "paper and glue".
    somker3 :I need the "paper and glue".
    -------------------------------------------
    Producer:I offered the "paper and glue".
    somker3 :I need the "paper and glue".
    -------------------------------------------
    Producer:I offered the "paper and glue".
    somker3 :I need the "paper and glue".
    -------------------------------------------
    Producer:I offered the "tobacco and paper".
    somker1 :I need the "tobacco and paper".
    -------------------------------------------
    Producer:I offered the "tobacco and paper".
    somker1 :I need the "tobacco and paper".
    -------------------------------------------
    

Java基础之——Java 线程相关推荐

  1. Java基础教程-10-多线程

    Java基础教程-10-多线程 1. 多线程 我们在之前,学习的程序在没有跳转语句的前提下,都是由上至下依次执行,那现在想要设计一个程序,边打游戏边听歌,怎么设计? 要解决上述问题,咱们得使用多进程或 ...

  2. java基础总结-java技术栈快速复习

    java基础 java基础概念 java概述和语言背景 java语言是没有sun公司(Stanford University Network:斯坦福大学网络)在1995年推出的计算机语言 java之父 ...

  3. 黑马程序员:Java基础总结----Java语言编程规范

       黑马程序员:Java基础总结        Java语言编程规范:参考自SUN公司文档  ASP.Net+Android+IO开发..Net培训.期待与您交流!  I.   排版规范 A.  规 ...

  4. java基础之java类型

    系列文章目录 java基础之java类型 文章目录 系列文章目录 基本类型 自动类型提升 引用类型 基本类型 整型 Byte 8位 -2^7~2^7-1 默认值0 Short 16位 -2^15~2^ ...

  5. Java 基础学习-Java语言概述

    Java 基础学习 第一章 Java语言概述 回顾java基础知识,进行整理记录. 文章目录 Java 基础学习 前言 一. Java语言发展史(了解) 二.Java语言跨平台原理(理解) 三.JRE ...

  6. Java 基础-01 Java语言入门

    文章目录 Java 基础-01 Java语言入门 1.计算机基本概念 1.1 计算机概述 1.2 计算机组成 1.3 CPU.内存与硬盘 2.软件基本概念 2.1 软件概述 2.2 人机交互方式 2. ...

  7. java基础之java中的基本数据类型

    java基础之java中的基本数据类型 学习java一段时间了,使用java也差不多一年多了,可是对于后续的java的学习真的是后劲不足,或者是说懒惰吧,回想一下这一年多,用java最多的就是Andr ...

  8. java基础之----java常见异常及代码示例

    java基础之----java常见异常及代码示例 参考文章: (1)java基础之----java常见异常及代码示例 (2)https://www.cnblogs.com/gunduzi/p/1203 ...

  9. 【Java基础】· Java基本语法:程序流程控制习题总结

    写在前面 Hello大家好, 我是[麟-小白],一位软件工程专业的学生,喜好计算机知识.希望大家能够一起学习进步呀!本人是一名在读大学生,专业水平有限,如发现错误或不足之处,请多多指正!谢谢大家!!! ...

  10. java基础:Java七大外企经典面试精讲视频

    java基础:Java七大外企经典面试精讲视频 对于很多应聘java程序员的求职者来说,全面掌握java面试技巧,确实是自己找到一个好工作的敲门砖.今天小编在这里给大家分享一个关于java基础的Jav ...

最新文章

  1. 使用Junit4时问题
  2. java019异常、File类
  3. 鼠标绘图 c语言,c语言高级编程技术教程 图形显示方式与鼠标输入.doc
  4. vue-cli教程(一)
  5. mysql 连接查询_Swoole 实战:MySQL 查询器的实现(协程连接池)
  6. 自动发现_清华发布首个自动图学习框架,或有助于蛋白质建模和新药发现
  7. linux应用之----多线程
  8. jms spring_JMS和Spring:有时很重要的小事情
  9. java返回类型自动_java-Apache Flink:由于类型擦除,无法自动确定函数的返回类型...
  10. Laravel同时接收路由参数和查询字符串中的参数
  11. html设置布局颜色设置,css布局中置背景颜色
  12. Docker在linux下的安装
  13. leetcode力扣36.有效的数独
  14. 欧姆龙编程软件SysmacStudio卸载方法
  15. NB-IOT之一个完整的BC95 UDP从开机到数据发送接收过程
  16. STM32单片机PT100温度采集控制系统
  17. SpringBoot分布式项目实现Session共享
  18. html 脚本错误,脚本错误怎么解决,教您脚本错误怎么解决?
  19. 外卖优惠券cps系统每日领团饿了么外卖券CPS系统公众号小程序源码
  20. 苹果吃鸡蓝牙耳机推荐哪个?性价比高的游戏蓝牙耳机推荐

热门文章

  1. 2022年危险化学品经营单位主要负责人特种作业证考试题库模拟考试平台操作
  2. nodejs第五天 npm yarn pnpm 包管理器
  3. 在html中active什么状态,javascript – 为什么html选项卡在设置为active时不显示其内容?...
  4. 《信号与系统》—MATLAB分析与实现(二)
  5. vSLAM研究综述:2010-2016
  6. 对NFT许可的观察:事实与虚构
  7. 采用光旁路保护(2×2机械式光开关)的数字光纤直放站及实现方法
  8. 【visum工作笔记】之一
  9. BEA WebLogic 和 INTERWOVEN TEAMSITE的集成
  10. Я пpoшý eró гoвоpйть мéдленно.的翻译和不定式成份和不定式做的句子成份...