Java多线程同步
对于多线程的同步,大家就牢记并学会一个关键字synchronized就OK了,很简单。
首先,理解同步。当多个线程需要共享资源时,它们需要某种方法来确定资源在某一刻仅被一个线程占用。达到此目的的过程叫做同步(synchronization)。由于多线程中的每个线程是单一的顺序控制流程,但它们共享一个进程的内存。这就产生一个问题:当多个线程同时操作一个进程内存中的对象时,产生不确定情况。为了协调多个线程,就形成一个约定:我用的时候你不要用,等着,当我用完,你再用。于是产生了多线程的同步。
同步的关键是管程(也叫信号量semaphore)的概念。管程是一个互斥独占锁定的对象,或称互斥体(mutex)。在给定的时间,仅有一个线程可以获得管程。当一个线程需要锁定,它必须进入管程,所有其他的试图进入已经锁定的管程必须挂起直到第一个线程退出管程,这些其他的线程被称为等待管程。一个拥有管程的线程如果愿意的话可以再次进入相同的管程。
以上是书面用语,打个比方,管程就是一把钥匙,而且是唯一的一把。线程好比一个人,把管程所对应的对象看成一个只能容纳一人的房间。OK,当一个”人“获得了“该房间”的“钥匙”后,进入“房间”内,其他”人“必须在“房间”外等候。只有当之前”那个人“走出房间,“钥匙”交给”下一个人“,”下一个人“才能进去。当然,如果上一个人不想交出钥匙,那他就完全可以不交,待在房间就行。
Java语言中同步很简单。因为所有对象都有它们与之对应的隐式管程。进入某一对象的管程,就是调用被synchronized关键字修饰的方法。当一个线程在一个同步方法内部,所有试图调用该方法的同实例的其他线程必须等待。为了退出管程,并放弃对对象的控制权给其他等待的线程,拥有管程的线程仅需从同步方法中返回。最经典例子:生产者与消费者问题,如下:
package 多线程同步; /* * 创建生产者类,实现Runnable接口 */ public class Producer implements Runnable { //创建生产商名字,生产仓库 private String producerName = null; private StoreHouse storeHouse = null; // 通过构造方法传入生产商名字,生产仓库 public Producer(String producerName,StoreHouse storeHouse){ this.producerName=producerName; this.storeHouse=storeHouse; } // 设置生产商名字 public void setProducerName(String producerName){ this.producerName=producerName; } // 返回生产商名字 public String getProducerName(){ return producerName; } // 生产商品 public void produceProduct(){ int i=0; while(true){ i++; Product pro = new Product(i);//生产产品 storeHouse.push(pro); //将产品放入仓库 System.out.println(getProducerName()+"生产了"+pro);//打印生产信息 try { Thread.sleep(2000); } catch (InterruptedException e) { return; } } } public void run() { produceProduct(); } }
package 多线程同步; /* * 创建顾客类,实现Runnable接口 */ public class Consumer implements Runnable { private String consumerName = null;//创建顾客名 private StoreHouse storeHouse = null;//创建仓库 //通过构造方法传入顾客名,仓库 public Consumer(String consumerName,StoreHouse storeHouse){ this.consumerName=consumerName; this.storeHouse=storeHouse; } //设置顾客名 public void setConsumerName(String consumerName){ this.consumerName=consumerName; } //返回顾客名 public String getConsumerName(){ return consumerName; } //消费商品 public void consumerProduct(){ while(true){ System.out.println(getConsumerName()+"消费了"+storeHouse.pop());//打印消费信息 try { Thread.sleep(5000); } catch (InterruptedException e) { return; } } } public void run() { consumerProduct(); } }
package 多线程同步; /* * 创建商品类 */ public class Product { private int productId = 0; //创建商品ID // 通过构造方法传入商品ID public Product (int productId){ this.productId=productId; } // 返回商品ID public int getProductId(){ return productId; } // 将ID转换为字符串形式 public String toString(){ return Integer.toString(productId); } }
package 多线程同步; /** * * 创建仓库类 * */ public class StoreHouse { //创建两计数变量和设置仓库库存大小 private int base=0; private int top=0; private Product[] products=new Product[10]; // 入库方法 public synchronized void push(Product product) { //判断库存是否已满 while(top==products.length){ notify();//库存已满,唤醒顾客(消费)线程 try { System.out.println("仓库已满,正等待消费..."); wait();//使生产线程进入等待队列状态 } catch (InterruptedException e) { System.out.println("stop push product because other reasons"); } } products[top] = product;//仓库未满,将产品入库,计数变量+1 top++; } // 出库方法 public synchronized Product pop(){ Product pro= null; //判断仓库是否有商品 while(top==base){ notify();//仓库已空,唤醒生产线程 try { System.out.println("仓库已空,正等待生产..."); wait();//使消费线程进入等待队列状态 } catch (InterruptedException e) { System.out.println("stop pop product beacuse other reasons"); } } top--; pro = products[top];//将产品出库 products[top]= null; return pro; } }
package 多线程同步; public class Synch { public static void main(String[] args) { StoreHouse storeHouse = new StoreHouse(); Producer producer = new Producer("生产者",storeHouse); Consumer consumer = new Consumer("消费者",storeHouse); Thread t1 = new Thread(producer); Thread t2 = new Thread(consumer); t1.start(); t2.start(); } }
需要注意死锁问题:
如果生产的速度大于消费的速度就会导致供大于求,仓库很容易就满了,然而生产者又一直关着仓库不放,没有机会给消费者使用,消费者不消费生产者就无法生产,所以就造成了死锁。解决的方法是在两个同步互斥方法中使用wait()和notify()方法。
wait()是Object类的方法,它的作用是拥有互斥锁的线程放弃锁的使用权,进入wait池进 等待,那么互斥锁就有可能被其他线程获得以执行其他任务。Notify()也是Object类的方法它的作用是从wait池中唤醒一条正在等待的线程进入就绪状态,被唤醒的这条线程就很可能重新获得CPU和互斥锁来完成它的任务。OK,现在我们再回过头来看上一次博客关于线程的状态中的(4),(5),就不难理解了。
(注,本文资源来自清华大学出版社《高级程序语言(Java版)》,本文只是交流学习,无任何商业目的)
相关推荐
Java多线程同步是Java编程中关键的并发概念,它涉及到如何在多个线程访问共享资源时保持数据的一致性和完整性。`java.util.concurrent`包是Java提供的一个强大的并发工具库,它为开发者提供了多种线程安全的工具,...
"Java多线程同步.pdf" Java多线程同步是指在Java语言中,如何使用synchronized关键字和其他同步机制来确保多线程程序的正确执行。在Java语言中,synchronized关键字用于对方法或者代码块进行同步,但是仅仅使用...
Java多线程同步机制研究分析 Java多线程同步机制是Java编程语言中的一种机制,它允许多个线程同时执行,提高了系统资源的利用率和安全性。但是,多线程中最重要的问题是线程的同步和共享资源的访问保护。本文通过对...
"基于Java多线程同步的安全性研究" 本文主要研究了基于Java多线程同步的安全性问题,讨论了Java多线程同步机制的实现方法和安全性问题的解决方法。文章首先介绍了Java多线程同步的必要性和重要性,然后讨论了Java多...
"Java多线程同步机制的应用分析" Java多线程同步机制的应用分析是指在Java语言中,如何使用同步机制来保护临界区,以避免多线程之间的冲突和错误。该机制通过管程机制和同步语法来保护临界区,使得多线程可以安全...
java多线程同步互斥访问实例,对于初学者或是温故而知新的同道中人都是一个很好的学习资料
根据给定文件的信息,本篇文档是关于Java多线程同步技术在简易模拟售票系统中的应用研究。文档详细介绍了多线程的概念、如何在Java中创建线程、线程同步技术以及如何利用这些技术来解决共享资源访问时的数据一致性...
Java多线程同步是编程中一个非常重要的概念,特别是在并发编程和高并发系统设计中起到关键作用。在Java中,为了保证线程安全,避免数据竞争和不一致的状态,我们通常会使用同步机制来控制对共享资源的访问。本文将...
Java多线程同步是编程中一个非常重要的概念,特别是在并发编程中,用于解决多个线程访问共享资源时可能引发的数据不一致问题。本实例通过一个简单的火车票售票系统来演示同步机制的应用。 在这个实例中,我们创建了...
Java多线程同步是编程中一个重要的概念,特别是在并发编程中,它用于管理多个线程对共享资源的访问,防止数据的不一致性。线程同步是解决多线程并发问题的关键,确保线程按照一定的顺序执行,避免竞态条件。 线程在...
Java多线程同步详解 在Java编程中,多线程是一种常见的并发执行方式,它可以提高程序的执行效率,充分利用CPU资源。然而,多线程环境下数据的安全性问题不容忽视,这就引出了Java中的同步机制。本文将深入探讨Java...
### Java多线程同步机制在售票系统的实现 #### 一、引言 随着计算机硬件的发展,多核处理器已经成为主流配置,这为多线程编程提供了更广阔的应用场景。多线程能够充分利用多核处理器的优势,提高程序的并发性和...
Java多线程同步机制在网络售票系统中的应用是一个关键的话题,特别是在高并发环境下,如网络售票系统,正确地处理多线程同步是确保数据一致性、避免资源竞争和死锁的重要手段。下面将详细介绍Java多线程同步机制以及...
在探究Java多线程同步问题时,需要关注的关键知识点包括synchronized关键字的使用、JDK 5引入的java.util.concurrent.locks包下的锁机制、以及JDK 1.2中ThreadLocal类的使用。此外,了解JVM(Java虚拟机)在处理多...
Java多线程同步问题分析主要关注的是在并发环境中如何有效地管理共享资源,避免出现数据竞争和不一致性。在Java编程中,多线程是提升程序性能的重要手段,尤其是在服务器端应用和服务中。然而,当多个线程同时访问并...
Java多线程同步机制及其应用是Java编程中至关重要的一环,尤其在开发高并发、高性能的应用程序时,理解并掌握这些机制是必不可少的。本文档详细介绍了Java中多线程的相关概念、创建方式、线程管理、同步机制以及一个...
Java多线程同步是Java并发编程中的核心概念,它用于解决多线程环境下资源的并发访问问题,确保数据的一致性和完整性。在这个实例中,我们看到一个简单的火车票售票系统,它展示了如何使用`synchronized`关键字来实现...
Java多线程同步是软件开发中的重要概念,特别是在并发编程中。Java内置的`synchronized`关键字是实现线程同步的基础,它可以确保同一时间只有一个线程访问特定的代码块或方法,从而避免数据竞争和不一致的情况。然而...
多线程注意:wait()方法的调用要有判定条件常用 while () obj.wait(timeout, nanos); ... // Perform action appropriate to condition } synchronized会影响共享数据,但对其他语句的执行不会有规律了!