synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块。
1. synchronized 方法:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如:
public synchronized void accessVal(int newVal);
synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)。
在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的访问。
synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是 synchronized 块。
2. synchronized 块:通过 synchronized关键字来声明synchronized 块。语法如下:
synchronized(syncObject) {
//允许访问控制的代码
}
synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行,具体机制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。
notify()及notifyAll()是Object的方法,与Object的wait()方法配合使用,而且这三个方法必须在同步块中调用.
如下:
在线程1中执行如下代码
...
synchronized(obj1) //1.进入同步块
{
try {
...
obj1.wait(); //2.进入暂停状态
}catch (InterruptedException exp) {}
}
1.当前同步对象(monitor)为obj1,obj1是任一实例,若是同步方法,则同步对象是this.进入同步块后,obj1为锁定状态,锁定状态对obj1本身无任何影响,而其它线程执行到同一代码时,因不能获得锁,处于Block状态,一旦解锁,被block的线程自动继续执行.
2.调用obj1.wait()有两个作用,一是使线程进入等待状态,二是解锁obj1,这时被block的线程将获得锁.线程1要退出等待必须要由其它线程显式的调用obj1.notify()或notifyAll()方法.
如
...
synchronized(obj1)
{
...
obj1.notify(); //3. 向wait的线程发通知信息
...
}
...
若其它线程执行到此时,线程1处于wait状态,则wait状态解除,解除后,若线程1若得到锁就能继续执行,若有多个线程处于obj1的wait状态,notify将随机选一个线程激活,而notifyAll是同时解除所有的wait状态.
notifyAll()让等待某个对象K的所有线程离开阻塞状态,
notify()随机地选取等待某个对象K的线程,让它离开阻塞状态。
notify(),notifyAll()非常有用,在一个synchronized(lockObj)块中当调用lockObj.wait()时,线程就已经将锁放开来了,这时当另外一个线程调用lockObj.notify()时,等待的线程就会继续执行下去了。这是一种非常高效的线程同步机制。如果没有他,用sleep()来同步的话就太浪费时间了。
一个简单的例子:
thread1 receive data
thread2 pase received data
lockObj是buf
当buf中没有数据时,thread2中调用buf.wait释放锁,让thread1有机会执行。
当thread1收到数据时,调用buf.notify()通知thread1去处理收到的数据。
如果在同步块入口点阻塞,不须其它线程调用notify(),调了也没效果,同步块能自动获得锁
如果是wait造成了阻塞,须用notfiy()激活,这两个方法是配合使用
notify、notifyAll、wait :
主要是为了解决持有监视器钥匙的线程暂停等待另一线程完成时可能发生死锁的问题。wait()方法使调用线程等待,直到发生超时或另一线程调用同一对象的notify()或notifyAll()方法。wait() 方法的用法如下:wait()或wait(long timeoutPeriodInMilliseconds)前者等待被通知,后者等待超时或通知。线程调用wait()方法时,释放所持有的钥匙让另一等待线程进入监视区。notify()方法只唤醒一个等待线程,而notifyAll()唤醒所有等待该监视器的线程。注意,这些方法只能在监视区内调用。否则会输出一种RuntimeException类型的IllegaMonitorStateException异常状态。
够详细清楚的吧。
总之wait()让线程等待,notify()和notifyall()激活某个等待线程,其实就是撤销该线程的中断状态,从而使他们有机会再次运行
有时会遇到如下问题,程序的一部分在写数据,另一部分读数据,但有时会出现读部分超前写部分,
这就是典型的产生者/消耗者问题.
.wait:是一个线程睡眠,直到在相同的对象上调用notify或notifyAll
.notify:启动第一个在相同对象调用wait的线程
.notifyAll:启动在相同的对象调用wait的所有线程
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jackpk/archive/2010/08/09/5799991.aspx
分享到:
相关推荐
在Java中,synchronize关键字的使用可以分为两种情况:一种是修饰方法,另一种是修饰代码块。这两种情况都可以用来解决线程安全问题,但是它们有所不同。修饰方法可以将整个方法锁定,使得在同一时间内只有一个线程...
`synchronized`关键字有两种主要的使用方式:一种是在方法声明中使用,另一种则是在代码块中使用。 ##### 1. synchronized方法 在方法声明中添加`synchronized`关键字,可以将整个方法体变成同步代码块。例如: `...
`synchronized`关键字有三种用法: 1. **修饰实例方法**:这样做的效果是整个方法体都被锁定,任何时刻只有一个线程可以执行该方法。 2. **修饰静态方法**:等同于对类的Class对象加锁,所有实例共享同一把锁。 3. *...
当尝试调用`speak(5, 5)`时,由于存在两种可能的方法匹配方式(即,将两个整型参数分别映射到第一个方法的`double`和`int`参数,或者映射到第二个方法的`int`和`double`参数),Java编译器无法确定调用哪一个方法,...
在 Java 中,同步的实现方法有两种:使用 synchronized 关键字和使用 wait、notify、notifyAll 方法。使用 synchronized 关键字可以使得某个方法或代码块在多线程中同步执行,而使用 wait、notify、notifyAll 方法...
JAVA 中有两种创建多线程的方式: 1. 继承 Thread 类 创建一个继承自 Thread 的子类,并重写 run() 方法。在 run() 方法中编写线程要执行的任务。最后,创建线程对象并调用 start() 方法来启动线程。 2. 实现 ...
2. JAVA的线程同步:JAVA中的线程同步可以使用 synchronize 关键字来实现锁机制,确保线程安全。 四、网络编程 1. JAVA的Socket编程:JAVA中的Socket可以实现网络通信,Socket可以分为客户端Socket和服务器端...
线程同步是 Java 编程中的一种机制,用于控制多个线程之间的资源访问顺序,以避免线程之间的冲突和数据不一致。线程同步的目的就是避免线程“同步”执行,即让多个线程之间排队操作共享资源。 关于线程同步,需要...
包括 String 和 StringBuffer 的区别、ArrayList、Vector、LinkedList 的存储性能和特性、HashMap 和 Hashtable 的区别、final、finally、finalize 的区别、switch 语句的使用、多线程的实现方法、Java 中的流类型、...
Stateful Session Bean 与 Stateless Session Bean ,这两种的 Session Bean都可以将系统逻辑放在 method之中执行,不同的是 Stateful Session Bean 可以记录呼叫者的状态,因此通常来说,一个使用者会有一个相对应...
在这个例子中,`addOne`方法原本可能需要在Java中进行同步,但注释掉了`synchronize`块,这表明在JRuby中,开发者可以使用Ruby的并发控制机制,而不是Java的锁来管理线程安全。 JRuby的另一个重要特性是其与Java...
常见的方法主要有两种: 1. 继承 Thread 类 2. 实现 Runnable 接口 三、停止线程的方法 1. 调用 Thread 中的 stop() 方法(已弃用) 2. 使用退出标志,可以使线程正常退出,也就是当 run() 方法完成后终止线程。 ...
在Java中,有两种方式创建线程:继承Thread类或实现Runnable接口。继承Thread类时,需要重写Thread类的run()方法,将需要执行的代码放入其中;而实现Runnable接口则是在类中定义run()方法,并将该对象作为Thread类的...
本文旨在探讨这两种同步机制的特点、使用场景及其差异。 #### 二、synchronized 关键字 `synchronized`关键字是Java提供的内置同步机制之一。它提供了一种简单的、面向对象的方式来实现线程间的同步操作。 1. **...
软件开发SVN的使用方法和注意事项-Eclipse中SVN图标含义 在软件开发中,SVN(Subversion)是一种非常流行的版本控制系统,它可以帮助开发者们更好地管理代码、协作开发和追踪变更。Eclipse 是一个流行的集成开发...
Brian Goetz对两种锁在JDK1.5、单核处理器及双Xeon处理器环境下做了一组吞吐量对比的实验,发现多线程环境下,synchronized的吞吐量下降的非常严重,而ReentrankLock则能基本保持在同一个比较稳定的水平上。...
使用类再生的两个方式:组合(new)和继承(extends),这个已经在 thinking in java中提到过. 设计模式之 Proxy(代理) 以 Jive 为例,剖析代理模式在用户级别授权机制上的应用 设计模式之 Facade(门面?) 可扩展的使用...
这个实现使用 volatile 关键字来确保 singleton 对象的可见性,并使用 synchronize 关键字来同步getInstance() 方法,使其成为原子操作。 单例模式是 Java 中一种常见的设计模式,用于确保某个类只有一个实例,并...
Service分为两种类型:Local Service(本地服务)和Remote Service(远程服务)。本地服务只能供本应用程序使用,而远程服务则可以通过进程间通信(IPC)被其他应用访问。 2. 主线程(Main thread):在Android应用...