Java多线程同步的一层对象/二层对象/三层对象写法对比

Java面试深度追问逻辑:从HashMap到JVM的三层穿透 HashMap底层实现原理与JVM内存模型是Java工程师的核心基础概念,其本质是理解数据结构在内存中的组织方式与运行时行为约束。原理层面涉及哈希算法设计、数组扩容机制、红黑树转换条件及内存可见性保障;技术价值体现在高并发场景下的线程安全边界、GC行为可预测性与故障定位效率;典型应用场景覆盖电商库存扣减、订单对账、微服务启动优化等生产环境。本文基于真实面试切片,聚焦HashMap链表转红黑树阈值、JVM元空间迁移、volatile内存屏障等高频热词,还原从知识复述到机制推演再到业务归因的能力跃迁路径。 阅读详情


前言:

在面向对象的思想下,线程的写法根据要创建的对象层级可以分为三种写法:

1,一层对象写法:采用extends Thread,复写父类的run()方法,直接建立一个线程实例对象的方式,这种方式简单,适用于单任务的单线程需求.在此不做过多讨论;

2,二层对象写法:采用implements Runnable接口,复写接口的run()方法,得到二级对象--通常称为任务对象;再通过将二级对象传入(负责main()方法的)一级对象的new Thread()构造参数,一级对象采用多态的Thread引用到run()方法;

import java.util.Random;
//两个线程一起买票的例子:

	class FinalDemo1 implements Runnable {
		private int[] arr = new int[6];
		private int n=0;
//		private int num = 50;

		public void run() {

			for (int i = 0; i < 100; i++) {
			synchronized(this){
					if (/*num > 0 &&*/ n<6) {
						try {
							Thread.sleep(10);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
//						System.out.println(Thread.currentThread().getName() + "卖出了第"
//								+ num-- + "张票!");
						
						arr[n]= new Random().nextInt(10);n++;
						for(int a:arr){System.out.print(a);}
                    	System.out.println();
					}
				}
			}
		}
	}


	public class MyThreadDemo2 {
		public static void main(String[] args) {
			FinalDemo1 f = new FinalDemo1();

			new Thread(f, "A").start();
			new Thread(f, "B").start();
			new Thread(f, "C").start();

		}
	}

二层写法要注意:共享的资源一般写在私有属性上,因此建立线程时,不能new多个Runnable! 否则就是多线程执行多个相同的任务了;应该先new一个Runnable对象r,始终将这个对象传给多个new Thread(r)就行了.


3,三层对象写法:在二层写法的基础上,因为任务的复杂度,建立第三个对象--通常称为resource资源对象来负责建立不同的处理方法,常见的是一个生产式方法,一个消费式方法,或者要交替执行的两个其它方法;

因为资源是唯一的,有要共享的属性,所以更严谨的可以写成单例;如此,new Thread(new Runnable(res))形成三层对象完成一个线程的定义,并且多个任务的多个线程,都共同操作着一个res,为保证安全,只需对res中的方法进行同步就欧了;

举两个例子:

一个任务,多个线程的例子: 虽然可以用二层对象写法,但是抽出第三层资源对象后,可以对线程任务更好控制,如交替执行;

//两个线程填充一个数组问题:
import java.util.Random;

public class Test {

        /*
         * 声明一个共享数组,起两个线程,两个线程分别隔一段时间(可以写一个随机数),
         * 给数组中添加数据,每一个线程为数组添加3个数据即可。
         * 
         */
        public static void main(String[] args) {
                
                final ShareArr sharearr = ShareArr.getInstance();
                
                new Thread(new Runnable()
                {
                        public void run()
                        {
                                for(int i = 0;i<3;i++)
                                {
                                        sharearr.addNumFirst();
                                }
                        }
                }).start();
                
                //因为使用了三级设计,对资源的调用同一个对象,因此不同的方法仍然共享private的属性,因此两个线程的第"i+1"个元素可以同步;
                new Thread(new Runnable()
                {
                        public void run()
                        {
                                for(int i = 0;i<3;i++)
                                {
                                        sharearr.addNumSecond();
                                }
                        }
                }).start();
        }

}

class ShareArr 
{
        private ShareArr(){};
        private static ShareArr arr = null;
        public static ShareArr getInstance()
        {
                if(arr == null)
                {
                        synchronized (ShareArr.class)
                        {
                                if(arr == null)
                                {
                                        arr = new ShareArr();
                                }
                        }
                }
                return arr;
        }
        
        private int[] array = new int[6];
        private int i = 0;
        boolean flag = true;
        public synchronized void addNumFirst()
        {
                while(!flag)
                {
                        try {
                                this.wait();
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
                }
                try {
                        Thread.sleep(1000);
                } catch (InterruptedException e) {
                        e.printStackTrace();
                }
                int num = new Random().nextInt();
                System.out.println(Thread.currentThread().getName()+"给数组第"+(i+1)+"个元素赋值"+num);
                array[i++] = num;
                flag = false;
                this.notify();
        }
        
        public synchronized void addNumSecond()
        {
                while(flag)
                {
                        try {
                                this.wait();
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
                }
                try {
                        Thread.sleep(1000);
                } catch (InterruptedException e) {
                        e.printStackTrace();
                }
                int num = new Random().nextInt();
                System.out.println(Thread.currentThread().getName()+"给数组第"+(i+1)+"个元素赋值"+num);
                array[i++] = num;
                flag = true;
                this.notify();
        }
}


多任务,多线程的例子: 一般都得采用三层对象写法;

生产&消费的synchronized和lock方式例子:

ProducerConsumerDemo

class  ProducerConsumerDemo2
{
	public static void main(String[] args) 
	{
		Resource r=new Resource();

		Producer pro=new Producer(r);
		Consumer con=new Consumer(r);

		Thread t1=new Thread (pro);
		Thread t2=new Thread (pro);
		Thread t3=new Thread (con);
		Thread t4=new Thread (con);

		t1.start();
		t2.start();
		t3.start();
		t4.start();

		System.out.println("Hello World!");
	}
}

class Resource 
{
	private String name;
	private int count=1;
	private boolean flag=false;

	public synchronized void set(String name)
	{
		while(flag)
			try{wait();}catch(Exception e){}
		this.name=name+"--"+count++;
		System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
		flag=true;
		this.notifyAll();
	}
	public synchronized void out()
	{
		while(!flag)
			try{wait();}catch(Exception e){}
		System.out.println(Thread.currentThread().getName()+"......消费者..."+this.name);
		flag=false;
		this.notifyAll();
	}
}

class Producer implements Runnable
{
	private Resource res;
	Producer(Resource res)
	{
		this.res=res;
	}
	public void run()
	{
		while (true)
		{
			res.set("+商品+");
		}
	}
}

class Consumer implements Runnable
{
	private Resource res;
	Consumer(Resource res)
	{
		this.res=res;
	}
	public void run()
	{
		while(true)
		{
			res.out();
		}
	}
}


import java.util.concurrent.locks.*;

class  ProducerConsumerDemo2
{
	public static void main(String[] args) 
	{
		Resource r=new Resource();

		Producer pro=new Producer(r);
		Consumer con=new Consumer(r);

		Thread t1=new Thread (pro);
		Thread t2=new Thread (pro);
		Thread t3=new Thread (con);
		Thread t4=new Thread (con);

		t1.start();
		t2.start();
		t3.start();
		t4.start();

		System.out.println("Hello World!");
	}
}


class Resource 
{
	private String name;
	private int count=1;
	private boolean flag=false;

	private Lock lock=new ReentrantLock();//接口类
	private Condition condition_pro=lock.newCondition();
	private Condition condition_con=lock.newCondition();
	
	public void set(String name)throws InterruptedException//中断异常
	{
		lock.lock();
		try{
			while(flag)

				condition_pro.await();//condition的抛异wait常方法,把pro的线程停止.

			this.name=name+"--"+count++;
			System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
			flag=true;
			condition_con.signal();
		}
		finally
		{
			lock.unlock();
		}
		

	}
	public  void out()throws InterruptedException
	{
		lock.lock();
		try{
			while(!flag)

				condition_con.await();//try{wait();}catch(Exception e){}

			System.out.println(Thread.currentThread().getName()+"...消费者......"+this.name);
			flag=false;
			condition_pro.signal();//this.notifyAll();唤醒all
		}
		finally{
			lock.unlock();
		}
	}
}

class Producer implements Runnable
{
	private Resource res;
	Producer(Resource res)
	{
		this.res=res;
	}
	public void run()
	{
		while (true)
		{
			try
			{
				res.set("+商品+");
			}
			catch (InterruptedException e)
			{
			}
			
		}
	}
}

class Consumer implements Runnable
{
	private Resource res;
	Consumer(Resource res)
	{
		this.res=res;
	}
	public void run()
	{
		while(true)
		{
			try
			{
				res.out();
			}
			catch (InterruptedException e)
			{
			}
		}
	}
}


 

2017锐明Java校招笔试复盘:核心考点与答题策略 在Java技术体系中,无论是日常开发还是校招面试,扎实的基础知识始终是衡量工程师能力的重要标尺。从面向对象语法到集合框架,从多线程并发到JVM内存模型,这些看似基础的知识点往往决定了笔试的成败。本文以一套经典校招Java笔试试卷为切入点,系统梳理了HashMap的底层原理、线程池的核心参数、快速排序的边界条件等高频考点,并结合实际答题场景给出了时间分配、代码规范与边界处理等实用建议。同时,针对环境配置常见问题与八股文备考误区进行了延伸讨论,帮助读者在理解原理的基础上构建完整的知识网络,从容应对各类Java岗 阅读详情

相关推荐

Java停车场管理系统的队列实现与扩展

队列是一种先进先出(FIFO)的数据结构,在Java中被广泛用于存储和管理数据。在现实世界中,例如在餐馆等候区,顾客排队点餐,谁先来谁先被服务,体现了队列的先进先出原则。在停车场系统中,车辆是一个核心对象。车辆类通常包含车辆的标识信息、状态信息等属性。车辆标识信息包括车牌号,车型等,状态信息可能包括停车状态(已停、未停)、入场时间、停车费用等。代码块示例:// 车牌号// 车型// 停车状态// 入场时间// 停车费// 构造方法、getter和setter省略。

weixin_36064575的博客 683

java多线程写在哪一层_面试知识点三:Java多线程

35.并行和并发有什么区别?36.线程和进程的区别?37.守护线程是什么?38.创建线程有哪几种方式?39.说一下 runnable 和 callable 有什么区别?40.线程有哪些状态?41.sleep() 和 wait() 有什么区别?42.notify()和 notifyAll()有什么区别?43.线程的 run()和 start()有什么区别?44.创建线程池有哪几种方式?45.线程池都...

weixin_33419305的博客 632

Java写的局域网双人象棋对战程序,带图形界面和实时聊天

一套开箱即用的Java中国象棋对战程序,分客户端和服务端两个独立可执行模块,支持局域网或自定义IP连接。启动客户端后能设置昵称、选头像、填服务器地址登录;进入大厅能看到当前在线玩家列表,点击空座位即可自动匹配对手开始对局。游戏完全遵循中国象棋规则,支持红黑方轮流走子、超时自动判负、悔棋一次、主动认输、发起求和、中途退出等操作;对局中双方可通过底部聊天框发送文字消息交流。资源包里包含全部源代码(src)、编译好的class文件(bin)、棋子图片(img/qizi)、玩家头像(img/face)、音效资源(a

2a4s6d8f0g的博客 243

面向对象 复习(二)

代码块       概述   在Java中,使用{}括起来的代码被称为代码块。      代码块分类   根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代码块(多线程讲解)。      常见代码块的应用    局部代码块    在方法中出现;限定变量生命

li_wei_song的专栏 451

STM32与FreeRTOS:基于TIM6的高精度系统时间获取实践

本文详细介绍了在STM32与FreeRTOS环境下,基于TIM6定时器实现高精度系统时间获取的实践方法。通过复用FreeRTOS的TIM6硬件资源,开发者可以高效获取毫秒级和微秒级系统时间,同时解决时间溢出和中断处理等关键问题。文章还提供了CubeMX配置技巧、代码实现及性能优化建议,适用于嵌入式系统开发中的精确时间管理需求。

weixin_29169505的博客 357

实施文档

流程管理 2008-04-23 09:44:00 874 收藏 3 分类专栏: 企业管理杂谈 文章标签: 文档 文档管理 项目管理 工作 配置管理 工具 项目实施文档是用来记录、描述、展示实施过程中一系列信息的处理过程,通过书面或图示的形式对项目活动过程或结果进行描述、定义、规定及报告。例如分阶段实施计划文档,标准业务流程文档,标准编码及数据文档,标准参数设置文档,功能操作指南文档。这些文档将会伴随着ERP实施的各个阶段逐渐充实、完善,也同时记载了整个实施的过程和成果。 作为实施顾问人员,在实施过程

qq_52337172的博客 1062

两个有层级的对象, 如何进行对比后赋值

需求: 我需要把图二中的description的值赋值到图一中 解决思路: 1. 把两个对象变成平级 export function flatten (data, c) { var result = {} for(var i in data) { if(typeof data[i] == 'object') Object.assign(result, flatten(data[i], c + '.' + i)) else result[(c + '.' + i).repl..

qq_43340606的博客 351

MATLAB新手必看:Stewart平台运动学逆解从入门到实战(附完整代码)

本文详细介绍了如何使用MATLAB实现Stewart平台的运动学逆解,从基础原理到完整代码实现,涵盖并联机器人的数学建模、MATLAB编程和Simulink集成。通过实战案例和可视化分析,帮助新手快速掌握Stewart平台的运动学逆解技术,适用于机器人学和控制理论领域的研究与应用。

dream的博客 551

非线性动力学中的同步,同步有哪几类?

同步被视为,耦合非线性振子的同步行为; 非线性动力学中的同步,同步有哪几类? 同步分为: 1、complete synchronization; 2、anti-synchronization; 3、phase synchronization; 4、generalized(广义) synchronization; 5、chimera(嵌合体) ...

Kp0fS的草稿纸 642

雷电模拟器+Google Play服务配置全指南:从安装到定位问题解决

本文详细介绍了雷电模拟器配置Google Play服务的全流程,包括版本选择、组件安装、定位服务调试及网络问题排查。针对安卓开发者的常见挑战,提供从基础到高级的解决方案,帮助优化测试环境稳定性与定位精度。

weixin_30399821的博客 1237

Camera AF和FF

Camera按对焦功能可以分为FF(Fixed Focus)和AF(Auto Focus),即固定对焦和自动对焦。固定对焦顾名思义就是焦距是固定的,而自动对焦可以通过移动镜头位置来改变焦距从而实现自动对焦。以前摄像的功能机大多是固定对焦,现在的手机都带有自动对焦功能。 FF模组包括镜头(Lens),传感器(Sensor),红外滤色器(IR Filter),电路板(PCB),镜头支撑(Lens Holder),连接器(Connector)。 Fig 1. FF Module AF模组包括FF模组,音圈马达(V

Coppa的博客 1万+

数据结构习题三层价值:从算法思维到工程实战的进阶指南

数据结构是计算机科学的核心基础,它研究数据的组织、存储和操作方式,直接影响算法的效率与程序的性能。其核心原理在于通过抽象建模,将现实问题映射为可计算的数据关系,并利用特定结构的特性(如数组的随机访问、链表的动态增删、哈希表的快速查找)来优化操作。掌握数据结构的技术价值在于培养“将抽象问题映射到具体数据模型,并利用模型特性设计高效算法”的底层思维能力,这是区分代码实现者与问题解决者的关键。在实际应用场景中,这种能力不仅用于解决算法面试题,更贯穿于系统设计、性能优化和并发编程等工程实践。例如,在实现**LRU缓

weixin_34268579的博客 354

Flow Match 原理 及应用

Flow Matching(流匹配)是生成模型的范式革命——用确定性ODE替代随机扩散过程,在自动驾驶轨迹预测中实现10倍采样加速和更高生成质量。更快的采样速度:通常只需 10-50 步就能生成高质量样本更稳定的训练:避免了传统扩散模型中复杂的噪声调度理论基础:基于连续正规化流(Continuous Normalizing Flows)核心思想:Flow Matching 通过学习一个 向量场(vector field) 来直接建模从噪声分布到目标分布的连续变换路径。

@bangbang的博客 99

Java学习Day7---多线程与多进程

例题: 7、多线程与多进程的主要区别之一就是共享资源,多线程是通过互斥访问来协调共享资源,在Windows系统中使用什么对象使多线程之间对资源互斥访问( ) A. SysTherad B. InitTherad C. Mutex D. Select 参考答案:C (Mutex:互斥 ) 首先了解一下多线程与多进程 [多线程还是多进程的选择及区别的博文,感觉这篇博文写的...

weixin_43606241的博客 402

UNet改进(54):当医学图像分割遇上频域学习与自监督

本文提出了一种改进U-Net的方法,通过频域增强模块和代理任务模块提升医学图像分割性能。频域增强模块在傅里叶空间对特征图进行可学习的频率调制,重点增强高频细节特征;代理任务模块通过图像重建约束编码器保留关键信息。两个模块协同工作,在仅增加5%参数量的情况下,形成空间域、频域和重建约束三条互补的信息路径。该方法特别适用于需要精细边缘分割的医学图像任务,预期能提升5%-10%的边缘分割精度,在小样本场景效果更显著。部署时可移除代理任务模块,不影响推理效率。未来可探索空间自适应频域调制和更丰富的代理任务设计。

2501_91516851的博客 227

LeRobot 机器人学习(Robot Learning)教程(二)经典机器人学

本文探讨了机器人学中基于学习的方法与传统动力学方法的对比与发展趋势。文章指出,传统方法依赖精确的动力学模型和大量人工调参,面临跨任务泛化能力弱、工程复杂度高、物理建模局限性等问题。随着机器学习技术的进步和机器人数据集的丰富,基于学习的方法展现出三大优势:(1)能够实现跨任务与实体的泛化;(2)降低对人类专业知识的依赖;(3)利用历史数据优化性能。文中以平面机械臂为例,分析了传统逆运动学方法的计算复杂性和环境适应性挑战,并指出基于学习的方案在处理高维感知输入、复杂接触动力学等方面具有明显优势。文章认为,结合物

2506_90492529的博客 1066

Java八股文——并发编程「并发安全篇」

面试官您好,AQS,全称是,它是JUC包中绝大多数锁和同步器的核心实现框架。您可以把它理解为一个“同步器开发的模板或蓝图”。像我们常用的Semaphore等,它们的底层都是基于AQS来实现的。AQS帮助开发者屏蔽了大量复杂的底层细节,比如线程的排队、阻塞、唤醒以及CAS操作等,让我们能更专注于实现同步器本身的逻辑。1. AQS的核心设计思想AQS的核心思想是,如果被请求的共享资源是空闲的,那么就将当前请求资源的线程设置为有效的工作线程,并将共享资源设置为锁定状态。

最短的捷径就是绕远路,绕远路才是我的最短捷径。 1418

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

单例模式中的饿汉和懒汉模式

一.饿汉模式 二.懒汉模式

weixin_47651920的博客 2万+

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

多线程与分布式:从单机到集群的演进

多线程和分布式是两种不同的并发处理方式。多线程在单个进程内通过共享内存实现并发,旨在提高单机性能;而分布式通过多台机器协作,解决水平扩展和高可用问题。两者在现代系统中协同工作,如电商下单流程中同时使用多线程处理请求和分布式调用服务。分布式环境带来新挑战,如需要分布式锁、事务一致性方案和缓存同步机制。虽然分布式增加了复杂度,但对大规模互联网应用至关重要。学习路径建议从JVM并发基础到分布式理论,再到Redis、消息队列等实践。

2301_80215285的博客 539

Java之volatile的实现

volatilevolatile指令重排 上一篇说了Java的内存模型,并留下“volatile的可见性就一定是立即可见的吗?synchronize了有为何还需要volatile?”的疑问,这篇文章试着讲讲它们的恩恩怨怨。 volatile volatile有两层语义,第一层保证不同线程间的可见性;第二层则是禁止指令重排。针对第一层,我们在Java内存模型一文中已分析,它通过load...

legendaryhaha的博客 351

懒汉式单例中使用双重检测详解

一、前言 本文的目的是探讨懒汉式单例为什么一定要使用双层if (instance == null)来保证多线程情况下安全运行,文章第二部分是双层检测的合理性,第三部分是双层检测的局限性,相互对应,从浅到深。 二、双层检测的合理性 2.1 双层检测的理论解释 问题1:单例模式在多线程环境下的lazy模式为什么要加两个if(instance == null)? 回答1:第一层 if (instance == null)是为了减少线程对同步锁锁的竞争,第二层if(instance==nul)是保证单例。

Ricartc的编程梦 2266

Java多线程面试3天冲刺:从锁机制到线程池与线上排查

Java后端面试中,多线程与并发编程是绕不开的高频考点,许多候选人能背诵synchronized与volatile的区别,却在面对线程池参数调优、线上死锁排查时语塞。真正的面试考察并非孤立概念,而是从线程状态流转、JMM内存模型、锁升级原理,到JUC工具如ConcurrentHashMap、ThreadLocal,再到线程池拒绝策略与线上jstack分析的完整链路。掌握这些基础知识,理解CAS、AQS等底层机制,才能在实际场景中应对多线程累加、Spring Boot并发请求等问题。本文以3天冲刺节奏,系统串

weixin_33907511的博客 437

2017新奥特Java校招笔试题全解析:从基础到并发,吃透这套就够了

Java基础语法、集合框架、JVM内存模型和多线程并发,是每一位Java工程师绕不开的核心功底,也是企业校招笔试中最常考察的能力维度。理解这些底层原理,不仅能在面试中从容应对连环追问,更能帮助开发者在实际项目中做出合理的性能优化和并发设计。本文从Java基础语法与面向对象思想入手,逐步深入到集合框架的底层实现、JVM内存分区与垃圾回收机制、线程池与锁的运用,并结合笔试中典型的算法题型,讲解各知识点的考察意图与工程实践。通过拆解一套2017年的Java校招真题,为准备校招或系统梳理基础的同学,划出一条清晰的能

weixin_34392435的博客 380

JAVA面试题——初级

1、关于常用包 java.long 基础包:String Math Integer… java.util 工具包:Collection Map Date java.sql 数据库相关:Conection java.io 输入输出:OutputStream File 2、JDK、JRE、JVMA的区别 JDK:是java开发的工具箱,包含jre,还包含将java文件编译为class文件的javac工具类(编译器),除此之外还包括java原生的API;包含J2SE(标准版)、J2EE(企业版)、J2ME(用于移

web18334137065的博客 152

Java多线程面试核心考点与底层原理深度解析

并发编程是现代软件系统的核心能力,而多线程是Java开发者绕不开的根基。理解进程与线程的区别、JMM内存模型、可见性与原子性等底层原理,是掌握并发编程的关键。无论是synchronized的锁升级机制、volatile的可见性保障,还是线程池参数调优、AQS队列同步器,都为高并发场景下的性能优化提供了技术支撑。在实际应用中,从ThreadLocal的内存泄漏防范,到线上死锁排查与jstack分析,再到Redis单线程模型的辩证思考,都体现了并发知识在工程实践中的价值。本文围绕Java多线程面试高频考点,系统

weixin_29201859的博客 263
上一篇: Java泛型总结(集合泛型、方法泛型、通配符)
下一篇: Java动态代理和AOP编程
marching21
博客等级 码龄12年 0粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值