目錄
一、程式、行程、執行緒
2.1 繼承Thread類別重寫run()方法
具體實作
2.2 实现Runnable接口实现run()方法
具体实现
使用匿名内部类
2.3 实现Callable接口
Callable和Thread、Runnable比较
三、线程的状态
3.1 基本四状态
3.2 等待状态
3.3 阻塞状态
四、线程常用的方法
4.1 线程休眠(sleep)
4.2 线程放弃(yield)
4.3 线程加入(join)
4.4 守护线程(setDaemon)
4.5 线程优先级(setPriority)
五、线程安全问题
5.1 卖票案例
5.2 同步代码块
5.3 同步方法
5.4 Lock锁
5.5 线程死锁
六、线程通信问题
6.1 wait()和wait(long timeout)
6.2 notify()和notifyAll()
6.3 生产者和消费者问题
首頁 Java java教程 詳細了解java多執行緒機制

詳細了解java多執行緒機制

Jun 17, 2022 pm 01:46 PM
java

本篇文章為大家帶來了關於java的相關知識,其中主要介紹了關於多線程的相關問題,包括了什麼是程序、進程、線程、創建線程的三種方式、線程的狀態等等內容,下面一起來看一下,希望對大家有幫助。

詳細了解java多執行緒機制

推薦學習:《java影片教學

一、程式、行程、執行緒

##1.1 什麼是程式

程式(program):是為完成特定任務、用某種語言編寫的一組指令的集合,是一段靜態的程式碼。 (程式是靜態的)

詳細了解java多執行緒機制

1.2 什麼是進程

進程(process):是程式的執行過程,正在運行的程序,進程作為資源分配的單位,在記憶體中會為每個進程分配不同的記憶體區域。 (進程是動態的)是一個動的過程,進程的生命週期: 有它自身的產生、存在和消亡的過程

詳細了解java多執行緒機制##目前作業系統都是支援多進程,可以同時執行多個進程,透過進程ID區分

詳細了解java多執行緒機制1.3 什麼是執行緒

執行緒(thread):進程中的一條執行路徑,也是CUP的基本調度單位,一個行程由一個或多個執行緒組成,彼此間完成不同的工作,多個執行緒同時執行,稱為多執行緒。

詳細了解java多執行緒機制
詳細了解java多執行緒機制#線程的組成

任何一個執行緒都具有的基本組成部分:

CPU時間片:作業系統(OS)會為每個執行緒分配執行時間。
  • 運行資料:堆空間(儲存執行緒需要使用的對象,多個執行緒可以共享堆中的對象);堆疊空間(儲存執行緒需要使用的局部變量,每個執行緒都擁有獨立的棧)
執行緒的特性

#執行緒搶佔式執行(效率高、可防止單一執行緒長時間獨佔CPU)
  • 單核心CPU在執行的時候,是按照時間片執行的,一個時間片只能執行一個線程,因為時間片特別的短,我們感受到的就是「同時」進行的。
  • 多核心CPU真正意義上做到了一個時間片多個執行緒同時進行
  • 在單核心CPU中,宏觀上同時進行,微觀上順序執行
1.4 行程和執行緒的區別

進程是作業系統中資源分配的基本單位,而執行緒是CPU的基本調度單位
  • 一個程式運行後至少有一個進程
  • 一個進程可以包含多個線程,但是至少需要有一個線程,否則這個進程是沒有意義的
  • 進程間不能共享資料段位址,但通進程的線程之間可以。
二、建立執行緒的三種方式

2.1 繼承Thread類別重寫run()方法

具體實作

1.繼承Thread類別
2.重寫run()方法

3.建立子類別物件
4.呼叫start()方法(
PS:不要呼叫run()方法,這樣相當於普通呼叫物件的方法,並為啟動執行緒

繼承類別

public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 1; i " + i);
        }
    }}
登入後複製

測試類別

public class TestThread {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        for (int i = 1; i "+i);
        }
    }}
登入後複製

結果


詳細了解java多執行緒機制取得線程ID和名稱

getId()

/ /取得線程的id,每個線程都有自己的idgetName()
//取得線程名字Thread.currentThread()
//取得當前線程

程式碼

public class TestThread {

	public static void main(String[] args) {
		MyThread t=new MyThread();
		t.start();
        //只能在继承Thread类的情况下用
		System.out.println("线程id:"+t.getId());
		System.out.println("线程名字:"+t.getName());
        //调用Thread类的静态方法获取当前线程(这里获取的是主线程)
		System.out.println("线程id:"+Thread.currentThread().getId());
		System.out.println("线程名字:"+Thread.currentThread().getName());
	}}
登入後複製

詳細了解java多執行緒機制#修改執行緒名稱

只能修改執行緒的名稱,不能修改線程的id(id是由系統自動分配)
1、使用線程子類別的建構方法賦值

2、呼叫線程物件的
setName()
方法

程式碼

#

public class MyThread extends Thread{
	public MyThread() {}//无参构造器
	public MyThread(String name) {
		super(name);
	}
	public void run() {
		for(int i=1;i<pre class="brush:php;toolbar:false">public class TestThread {

	public static void main(String[] args) {
		MyThread t1=new MyThread("子线程1");//通过构造方法
		MyThread t2=new MyThread();
		t2.setName("子线程2");
		System.out.println("线程t1的id:"+t1.getId()+" 名称:"+t1.getName());
		System.out.println("线程t2的id:"+t2.getId()+" 名称:"+t2.getName());
	}}
登入後複製

詳細了解java多執行緒機制

2.2 实现Runnable接口实现run()方法

具体实现

1.实现Runnable接口
2.实现run()方法
3.创建实现类对象
4.创建线程类对象
5.调用start()方法

实现接口

public class MyRunnable implements Runnable{//实现接口
	@Override
	public void run() {//实现run方法
		// TODO Auto-generated method stub
		for(int i=1;i<p><strong>测试类</strong></p><pre class="brush:php;toolbar:false">public class TestRunnable {
	public static void main(String[] args) {
		//1.创建MyRunnable对象,表示线程执行的功能
		Runnable runnable=new MyRunnable();
		//2.创建线程对象
		Thread th=new Thread(runnable);
		//3.启动线程
		th.start();
		for(int i=1;i<p><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/beb0b9e2f551ceb35ac7ab846edfec3d-8.png" class="lazy" alt="詳細了解java多執行緒機制"></p><h3 id="使用匿名内部类">使用匿名内部类</h3><blockquote><p>如果一个线程方法我们只使用一次,那么就不必设置一个单独的类,就可以使用匿名内部类实现该功能</p></blockquote><pre class="brush:php;toolbar:false">public class TestRunnable {
	public static void main(String[] args) {
		Runnable runnable=new Runnable() {			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				for(int i=1;i<h2 id="实现Callable接口">2.3 实现Callable接口</h2><h3 id="Callable和Thread-Runnable比较">Callable和Thread、Runnable比较</h3><blockquote>
<p>对比继承<code>Thread</code>类和实现<code>Runnable</code>接口创建线程的方式发现,都需要有一个<code>run()</code>方法,但是这个run()方法有不足:</p>
<ul>
<li>没有返回值</li>
<li>不能抛出异常</li>
</ul>
<p>基于上面的两个不足,在JDK1.5以后出现了第三种创建线程的方式:实现<code>Callable</code>接口</p>
<p>实现<code>Callable</code>接口的好处:</p>
<ul>
<li>有返回值</li>
<li>能抛出异常</li>
</ul>
<p>缺点:</p>
<ul><li>创建线程比较麻烦</li></ul>
</blockquote><blockquote>
<p>1.实现<code>Callable</code>接口,可以不带泛型,如果不带泛型,那么call方法的返回值就是<code>Object</code>类型</p>
<p>2.如果带泛型,那么call的返回值就是泛型对应的类型</p>
<p>3.从call方法看到:方法有返回值,可以抛出异常</p>
</blockquote><h3 id="具体实现">具体实现</h3><p><strong>实现接口</strong></p><pre class="brush:php;toolbar:false">import java.util.Random;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;public class TestCallable implements Callable<integer>{

	@Override
	public Integer call() throws Exception {
		// TODO Auto-generated method stub
		return new Random().nextInt(10);
	}}</integer>
登入後複製

测试类

import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;public class Test {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		TestCallable tc=new TestCallable();
		FutureTask<integer> ft=new FutureTask(tc);
		//创建线程对象
		Thread th=new Thread(ft);
		th.start();
		//获取线程得到的返回值
		Integer In=ft.get();
		System.out.println(In);
	}}</integer>
登入後複製

三、线程的状态

3.1 基本四状态

詳細了解java多執行緒機制

3.2 等待状态

詳細了解java多執行緒機制

3.3 阻塞状态

詳細了解java多執行緒機制

四、线程常用的方法

  • 休眠(当前线程主动休眠millis毫秒)public static void sleep(long millis)

  • 放弃(当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片)public static void yield()

  • 加入(当一个线程调用了join方法,这个线程就会先被执行,它执行结束以后才可以去执行其余的线程)public final void join()//必须先start(),在join(),才有效

  • 优先级(线程优先级为1–10,默认为5,优先级越高,表示获取CPU机会越多)线程对象.setPriority()

  • 守护线程

    • 线程对象.setDaemon(true);设置为守护线程
    • 线程有两类:用户线程(前台线程)、守护线程(后台线程)
    • 如果程序中所有前台线程都执行完毕了,后台线程也会自动结束
    • 垃圾回收器线程属于守护线程

4.1 线程休眠(sleep)

public static void sleep(long millis)当前线程主动休眠millis毫秒

子线程

public class SleepThread extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <p><mark>PS:sleep()的异常在run方法中是不能抛出的,只能用try–catch处理</mark><br><strong>测试类</strong></p><pre class="brush:php;toolbar:false">public class Test01 {
    public static void main(String[] args) {
        SleepThread sleepThread = new SleepThread();
        sleepThread.start();
    }}
登入後複製

结果:每次间隔100ms输出一次
詳細了解java多執行緒機制

4.2 线程放弃(yield)

public static void yield()当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片

子线程

public class YieldThread extends Thread{
    @Override
    public void run() {
        for (int i=1;i<p><strong>测试类</strong></p><pre class="brush:php;toolbar:false">public class Test01 {
    public static void main(String[] args) {
        YieldThread yieldThread01 = new YieldThread();
        YieldThread yieldThread02 = new YieldThread();
        yieldThread01.start();
        yieldThread02.start();
    }}
登入後複製

结果:基本都会交替进行,也会有一个线程连输出
詳細了解java多執行緒機制

4.3 线程加入(join)

当一个线程调用了join方法,这个线程就会先被执行,它执行结束以后才可以去执行其余的线程,必须先start,再join才有效

子线程

public class JoinThread extends Thread{
    @Override
    public void run() {
        for (int i=1;i<p><strong>测试类</strong></p><pre class="brush:php;toolbar:false">public class Test01 {
    public static void main(String[] args) throws InterruptedException {
        for (int i=1;i<p><strong>结果:当主线程打印到5的时候,这时候子线程加入进来,就先执行完子线程,在执行主线程</strong><br><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/da3747d2bd3ee6a154b0a90e8cc9f0a7-14.png" class="lazy" alt="詳細了解java多執行緒機制"></p><h2 id="守护线程-setDaemon">4.4 守护线程(setDaemon)</h2><blockquote><p>将子线程设置为主线程的伴随线程,主线程停止的时候,子线程也不要继续执行了<br> 注意:<strong>先设置,在启动</strong></p></blockquote><p><strong>子线程</strong></p><pre class="brush:php;toolbar:false">public class TestThread extends Thread{
    @Override
    public void run() {
        for(int i=1;i<p><strong>测试类</strong></p><pre class="brush:php;toolbar:false">public class Test01 {
    public static void main(String[] args) throws InterruptedException {
        TestThread daemonThread = new TestThread();
        daemonThread.setDaemon(true);//设置守护线程
        daemonThread.start();
        for (int i=1;i<p><strong>结果:当主线程结束时,子线程也跟着结束,并不会继续执行下去打印输出</strong><br><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/da3747d2bd3ee6a154b0a90e8cc9f0a7-15.png" class="lazy" alt="詳細了解java多執行緒機制"></p><h2 id="线程优先级-setPriority">4.5 线程优先级(setPriority)</h2><blockquote><p>线程优先级为1-10,默认为5,优先级越高,表示获取CPU机会越多<br><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/da3747d2bd3ee6a154b0a90e8cc9f0a7-16.png" class="lazy" alt="詳細了解java多執行緒機制"></p></blockquote><p><strong>子线程</strong></p><pre class="brush:php;toolbar:false">public class TestThread extends Thread{
    @Override
    public void run() {
        for(int i=1;i<p><strong>测试</strong></p><pre class="brush:php;toolbar:false">public class Test01 {
    public static void main(String[] args) throws InterruptedException {
        TestThread th1 = new TestThread();
        TestThread th2 = new TestThread();
        TestThread th3 = new TestThread();
        th1.setPriority(10);//设置线程1优先级10
        th1.start();
        th2.start();//线程2优先级默认不变,为5
        th3.setPriority(1);//设置线程3优先级为1
        th3.start();
    }}
登入後複製

结果:优先级(th1>th2>th3)线程3应该在最后打印
詳細了解java多執行緒機制

五、线程安全问题

5.1 卖票案例

需求:模拟三个窗口,每个窗口有100个人,同时抢10张票
詳細了解java多執行緒機制
使用继承Runnable接口的方法

public class BuyTicketRunnable implements Runnable{
	
	private int ticketNum=10;
	@Override
	public void run() {
		for(int i=1;i<p><strong>测试方法</strong></p><pre class="brush:php;toolbar:false">public class BuyTicketTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Runnable runnable=new BuyTicketRunnable();
		
		Thread th1=new Thread(runnable,"窗口1");
		Thread th2=new Thread(runnable,"窗口2");
		Thread th3=new Thread(runnable,"窗口3");
		
		th1.start();
		th2.start();
		th3.start();
	}}
登入後複製

结果
詳細了解java多執行緒機制

我们发现,不同窗口会抢到同一张票!!!,这在实际情况是不允许的,这是因为多个线程,在争抢资源的过程中,导致共享的资源出现问题。一个线程还没执行完,另一个线程就参与进来了,开始争抢。(但窗口2抢到第10张票,还没来得及ticketNum--操作,时间片就用完了,随后被窗口三抢到CPU资源,此时的票数还是10,窗口三也抢到第十张票,也还没来得及ticketNum--操作窗口三时间片由完了,窗口一抢到CPU资源,还是买到了第10张票)

多线程安全问题:

  • 当多线程并发访问临界资源时,如果破坏原子操作,可能会造成数据不一致
  • 临界资源:共享资源(同一对象),一次只能允许一个线程使用,才可以保证其正确性
  • 原子操作:不可分割的多步操作,被视作一个整体,其顺序和步骤不可被打乱或缺省

5.2 同步代码块

synchronized(同步监视器)

  • 必须是引用数据类型,不能是基本数据类型
  • 也可以创建一个专门的同步监视器,没有任何业务含义 (new Object)
  • 一般使用共享资源做同步监视器即可
  • 在同步代码块中不能改变同步监视器对象的引用
  • 尽量不要String和包装类Integer做同步监视器,建议使用final修饰同步监视器

对卖票案例改进

public class BuyTicketRunnable implements Runnable{
	static Object obj=new Object();
	private int ticketNum=10;
	@Override
	public void run() {
		for(int i=1;i<blockquote><ul>
<li>多个代码块使用了同一个同步监视器(锁),锁住一个代码块的同时,也锁住所有使用该锁的所有代码块,其他线程无法访问其中的任何一个代码块</li>
<li>多个代码块使用了同一个同步监视器(锁),锁住一个代码块的同时,也锁住所有使用该锁的所有代码块, 但是没有锁住使用其他同步监视器的代码块,其他线程有机会访问其他同步监视器的代码块</li>
</ul></blockquote><h2 id="同步方法">5.3 同步方法</h2><blockquote>
<p><code>synchronized</code>(同步方法)</p>
<ul>
<li>不要将run()定义为同步方法</li>
<li>非静态同步方法的同步监视器是this;静态同步方法(static)的同步监视器是 类名.class 字节码信息对象</li>
<li>同步代码块的效率要高于同步方法(原因:同步方法是将线程挡在了方法的外部,而同步代码块锁将线程挡在了代码块的外部,但是却是方法的内部)</li>
<li>同步方法的锁是this,一旦锁住一个方法,就锁住了所有的同步方法;同步代码块只是锁住使用该同步监视器的代码块,而没有锁住使用其他监视器的代码块</li>
</ul>
</blockquote><p><strong>买票案例改进</strong></p><pre class="brush:php;toolbar:false">public class BuyTicketRunnable implements Runnable{
	private int ticketNum=10;
	@Override
	public void run() {
		for(int i=1;i0) {
			System.out.println("在"+Thread.currentThread().getName()+"买到了第"+ticketNum+"张票!");
			ticketNum--;	
		}
	}}
登入後複製

5.4 Lock锁

Lock锁:

  • DK1.5后新增新一代的线程同步方式:Lock锁,与采用synchronized相比,lock可提供多种锁方案,更灵活
  • synchronized是Java中的关键字,这个关键字的识别是靠JVM来识别完成的呀。是虚拟机级别的。
    但是Lock锁是API级别的,提供了相应的接口和对应的实现类,这个方式更灵活,表现出来的性能优于之前的方式。

对买票案例改进

import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class BuyTicketRunnable implements Runnable{
	private int ticketNum=10;
	Lock lock=new ReentrantLock();//接口=实现类  可以使用不同的实现类
	@Override
	public void run() {
		for(int i=1;i0) {
					System.out.println("在"+Thread.currentThread().getName()+"买到了第"+ticketNum+"张票!");
					ticketNum--;	
				}
			}catch(Exception e) {
				e.printStackTrace();
			}finally {
				 //关闭锁:--->即使有异常,这个锁也可以得到释放
				lock.unlock();
			}
		}
	}}
登入後複製

Lock和synchronized的区别

  • Lock是显式锁(手动开启和关闭锁,别忘记关闭锁),synchronized是隐式锁
  • Lock只有代码块锁,synchronized有代码块锁和方法锁
  • 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)

5.5 线程死锁

  • 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
  • 出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续

*案例:男孩女孩一起去吃饭,但是桌子上只有两根筷子,如果两个人同时抢到一根筷子而不放弃,这样两个人都吃不上饭,这样就形成死锁了;必须要有一个人放弃争抢,等待另一个人用完,释放资源,这个人之后才会获得两根筷子,两个人才能都吃上饭 *

package 多线程;class Eat{
    //代表两个筷子
	public static Object o1=new Object();
	public static Object o2=new Object();
	public static void eat() {
		System.out.println("可以吃饭了");
	}}class BoyThread extends Thread{
	public void run() {
		synchronized (Eat.o1) {
			System.out.println("男孩拿到了第一根筷子!");
			synchronized (Eat.o2) {
				System.out.println("男孩拿到了第二根筷子!");
				Eat.eat();
			}
		}
	}}class GirlThread extends Thread{
	public void run() {
		synchronized (Eat.o2) {
			System.out.println("女孩拿到了第二根筷子!");
			synchronized (Eat.o1) {
				System.out.println("女孩拿到了第一根筷子!");
				Eat.eat();
			}
		}
	}}public class MyLock {
	public static void main(String[] args) {
		BoyThread boy=new BoyThread();
		GirlThread girl=new GirlThread();
		boy.start();
		girl.start();
	}}
登入後複製

结果
詳細了解java多執行緒機制
解决办法

先让男孩拿到筷子,线程休眠一下,等待男孩用完筷子,在启动女孩线程

public class MyLock {
	public static void main(String[] args) {
		BoyThread boy=new BoyThread();
		GirlThread girl=new GirlThread();
		boy.start();
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		girl.start();
	}}
登入後複製

詳細了解java多執行緒機制
在写程序中要避免这种死锁:减少同步资源的定义,避免嵌套同步

六、线程通信问题

在Java对象中,有两种池

  • 锁池(synchronized
  • 等待池(wait();notify();notifyAll()

如果一个线程调用了某个对象的wait方法,那么该线程进入到该对象的等待池中(并且已经将锁释放);
如果未来的某个时刻,另外一个线程调用了相同的对象notify方法或者notifyAll方法,那么该等待池中的线程就会被唤醒,然后进入到对象的锁池里面去获得该对象的锁;
如果获得锁成功后,那么该线程就会沿着wait方法之后的路径继续执行。注意:沿着wait方法之后执行

6.1 wait()和wait(long timeout)

  • wait():的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。直到其他线程调用此对象的notify() 方法或 notifyAll() 方法,当前线程被唤醒(进入就绪状态)
  • wait(long timeout):让当前线程处于“等待(阻塞)状态,直到其他线程调用此对象的notify()方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入就绪状态)

sleep和wait的区别:sleep进入阻塞状态没有释放锁,wait进入阻塞状态但是同时释放了锁

6.2 notify()和notifyAll()

notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程

  • notify()是唤醒单个线程
  • notifyAll()是唤醒所有的线程

6.3 生产者和消费者问题

案例:
假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中产品取走消费。
如果仓库中没有产品,则生产者将产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止。
如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,直到仓库中再次放入产品为止。
詳細了解java多執行緒機制

功能分解一:商品类

public class Product {//商品类
    private String name;//名字
    private String brand;//品牌
    boolean flag = false;//设置标记,false表示商品没有,等待生产者生产

    public synchronized void setProduct(String name, String brand) {//生产商品,同步方法,锁住的是this
        if (flag == true) {//如果flag为true,代表有商品,不生产,等待消费者消费
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //生产商品
        this.setName(name);
        this.setBrand(brand);

        System.out.println("生产者生产了" +this.getBrand() +this.getName());
        //生产完,设置标志
        flag = true;
        //唤醒消费线程
        notify();
    }

    public synchronized void getProduct() {
        if (flag == false) {//如果是false,则没有商品,等待生产者生产
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果有商品,消费
        System.out.println("消费者消费了" + this.getBrand() +this.getName());
        //设置标志
        flag = false;
        //唤醒线程
        notify();
    }


    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getBrand() {
        return brand;
    }}
登入後複製

功能分解二:生产者线程

public class ProducterThread extends Thread {//生产者线程
    private Product p;

    public ProducterThread(Product p) {
        this.p = p;
    }

    @Override
    public void run() {
        for (int i = 1; i <p><strong>功能分解三:消费者线程</strong></p><pre class="brush:php;toolbar:false">public class CustomerThread extends Thread {//消费者线程
    private Product pro;

    public CustomerThread(Product pro) {
        this.pro = pro;
    }

    @Override
    public void run() {
        for (int i = 1; i <p><strong>功能分解四:测试类</strong></p><pre class="brush:php;toolbar:false">public class Test {
    public static void main(String[] args) {
        Product p = new Product();
        ProducterThread pth = new ProducterThread(p);
        CustomerThread cth = new CustomerThread(p);
        pth.start();
        cth.start();
    }}
登入後複製

结果:生产者生产一件商品,消费者消费一件商品,交替进行

詳細了解java多執行緒機制

推薦學習:《java影片教學

以上是詳細了解java多執行緒機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Java 中的完美數 Java 中的完美數 Aug 30, 2024 pm 04:28 PM

Java 完美數指南。這裡我們討論定義,如何在 Java 中檢查完美數?

Java 中的隨機數產生器 Java 中的隨機數產生器 Aug 30, 2024 pm 04:27 PM

Java 隨機數產生器指南。在這裡,我們透過範例討論 Java 中的函數,並透過範例討論兩個不同的生成器。

Java中的Weka Java中的Weka Aug 30, 2024 pm 04:28 PM

Java 版 Weka 指南。這裡我們透過範例討論簡介、如何使用 weka java、平台類型和優點。

Java 中的史密斯數 Java 中的史密斯數 Aug 30, 2024 pm 04:28 PM

Java 史密斯數指南。這裡我們討論定義,如何在Java中檢查史密斯號?帶有程式碼實現的範例。

Java Spring 面試題 Java Spring 面試題 Aug 30, 2024 pm 04:29 PM

在本文中,我們保留了最常被問到的 Java Spring 面試問題及其詳細答案。這樣你就可以順利通過面試。

突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

Java 中的時間戳至今 Java 中的時間戳至今 Aug 30, 2024 pm 04:28 PM

Java 中的時間戳記到日期指南。這裡我們也結合範例討論了介紹以及如何在java中將時間戳記轉換為日期。

創造未來:零基礎的 Java 編程 創造未來:零基礎的 Java 編程 Oct 13, 2024 pm 01:32 PM

Java是熱門程式語言,適合初學者和經驗豐富的開發者學習。本教學從基礎概念出發,逐步深入解說進階主題。安裝Java開發工具包後,可透過建立簡單的「Hello,World!」程式來實踐程式設計。理解程式碼後,使用命令提示字元編譯並執行程序,控制台上將輸出「Hello,World!」。學習Java開啟了程式設計之旅,隨著掌握程度加深,可創建更複雜的應用程式。

See all articles