多线程之间的同步控制

简介: 问题:同时运行的几个线程需要共享一个数据,并且要考虑到彼此的状态和动作。例如,当一个线程对共享的数据进行操作时,在没有完成相关操作之前,不允许其他线程打断它,否则会破坏数据的完整性。也就是说,被多个线程共享的数据在同一时刻只允许一个线程处于操作之中。


问题:


同时运行的几个线程需要共享一个数据,并且要考虑到彼此的状态和动作。


例如,当一个线程对共享的数据进行操作时,在没有完成相关操作之前,不允许其他线程打断它,否则会破坏数据的完整性。也就是说,被多个线程共享的数据在同一时刻只允许一个线程处于操作之中。

 

实现原理:


    为了保证线程安全,使用“锁旗标”;

当线程A获得了一个对象的锁旗标后,线程B若也想获得该对象的锁旗标,就必须等待线程A完成规定的操作并释放出锁旗标后,才能获得该对象的锁旗标,并执行线程B中的操作。



代码实现:


public class ProducerAndConsumer {

	/**
	 * 假定开始售票处并没有票,一个线程往里存票,另一个线程则往外卖票。
	 * 新建一个票类对象,让存票和售票线程都访问它。
	 * 两个线程共享同一个数据对象来实现对同一份数据的操作
	 */
	public static void main(String[] args) {
		Tickets t=new Tickets(10); //新建一个票类对象,总票数作为参数
		new Producer(t).start(); //以票类对象为参数创建存票线程对象,并启动
		new Consumer(t).start();//以同一个票类对象为参数创建售票线程,并启动

	}

}

//票类
class Tickets{
	int number=0; //票号
	int size;	//总票数
	boolean available=false; //表示目前是否有票可售
	public Tickets(int size){this.size=size;}//构造函数,传入总票数参数
}

//存票线程
class Producer extends Thread{
	Tickets t=null;
	public Producer(Tickets t){this.t=t;}//构造函数:以一个票类为参数
	@Override
	public void run() {
		while(t.number<t.size){//限制循环条件为存票序号小于总票数
			synchronized(t){//申请对象t的锁旗标
				System.out.println("Producer puts ticket "+(++t.number));
				t.available=true;//可以买票
			}//自动释放锁旗标
			
		}
	}
}

//售票线程
class Consumer extends Thread{
	Tickets t=null;
	int i=0;
	public Consumer(Tickets t){//构造函数:以一个票类对象为参数
		this.t=t;
	}
	public void run(){
		
		synchronized(t){
			while(i<t.size){ //循环条件为售票序号小于总票数
				if(t.available==true && i<=t.number){ //有票可售且小于目前票序号
					System.out.println("consumer buys ticket "+(++i));
				}
				if(i==t.number){//当票已售到当前序号,则不可售
					t.available=false;
				}
			}
		}
		
	}
}


       一个对象的锁旗标只有一个,所以利用对一个对象锁旗标的争夺,可以实现不同线程的互斥效果。当一个线程获得锁旗标后,需要改锁旗标的其他线程只能处于等待状态。


      另外, 也可以将此关键字加在方法上:


//取票方法
	public synchronized void sell(){
		if(!available){ //如果没有存票,则售票线程等待
			try{
				wait();
			}
			catch(Exception e){
				
			}
			System.out.println("consumer buys ticket "+(number));
			available=false;
			notify();//售票唤醒存票线程开始存票
			if(number==size){
				number=size+1;//在售完最后一张票后,设置一个结束标志
			}//number>size表示售票结束
		}
	}







目录
相关文章
|
3月前
|
编解码 数据安全/隐私保护 计算机视觉
Opencv学习笔记(十):同步和异步(多线程)操作打开海康摄像头
如何使用OpenCV进行同步和异步操作来打开海康摄像头,并提供了相关的代码示例。
134 1
Opencv学习笔记(十):同步和异步(多线程)操作打开海康摄像头
|
5月前
|
Java 开发者 C++
Java多线程同步大揭秘:synchronized与Lock的终极对决!
Java多线程同步大揭秘:synchronized与Lock的终极对决!
96 5
|
2月前
|
Java 调度
Java 线程同步的四种方式,最全详解,建议收藏!
本文详细解析了Java线程同步的四种方式:synchronized关键字、ReentrantLock、原子变量和ThreadLocal,通过实例代码和对比分析,帮助你深入理解线程同步机制。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
Java 线程同步的四种方式,最全详解,建议收藏!
|
3月前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
59 1
|
3月前
|
安全 调度 C#
STA模型、同步上下文和多线程、异步调度
【10月更文挑战第19天】本文介绍了 STA 模型、同步上下文和多线程、异步调度的概念及其优缺点。STA 模型适用于单线程环境,确保资源访问的顺序性;同步上下文和多线程提高了程序的并发性和响应性,但增加了复杂性;异步调度提升了程序的响应性和资源利用率,但也带来了编程复杂性和错误处理的挑战。选择合适的模型需根据具体应用场景和需求进行权衡。
|
3月前
多线程通信和同步的方式有哪些?
【10月更文挑战第6天】
155 0
|
5月前
|
安全 Java 开发者
Java多线程同步:synchronized与Lock的“爱恨情仇”!
Java多线程同步:synchronized与Lock的“爱恨情仇”!
92 5
|
5月前
|
Java 程序员
从0到1,手把手教你玩转Java多线程同步!
从0到1,手把手教你玩转Java多线程同步!
49 3
|
5月前
|
Java 测试技术
Java多线程同步实战:从synchronized到Lock的进化之路!
Java多线程同步实战:从synchronized到Lock的进化之路!
109 1
|
5月前
|
存储 Java 开发者
HashMap线程安全问题大揭秘:ConcurrentHashMap、自定义同步,一文让你彻底解锁!
【8月更文挑战第24天】HashMap是Java集合框架中不可或缺的一部分,以其高效的键值对存储和快速访问能力广受开发者欢迎。本文深入探讨了HashMap在JDK 1.8后的底层结构——数组+链表+红黑树混合模式,这种设计既利用了数组的快速定位优势,又通过链表和红黑树有效解决了哈希冲突问题。数组作为基石,每个元素包含一个Node节点,通过next指针形成链表;当链表长度过长时,采用红黑树进行优化,显著提升性能。此外,还介绍了HashMap的扩容机制,确保即使在数据量增大时也能保持高效运作。通过示例代码展示如何使用HashMap进行基本操作,帮助理解其实现原理及应用场景。
75 1