synchronized 保证 锁定的对象在同一时间只有一个线程在执行 synchronized块中的东西!
在使用 synchronized 搞清楚synchronized锁定的是哪个对象,自己到底需要对那个对象 保证线程安全!
列子 一枚:
调用 毁掉函数的地方:
public Value get(Key key, long timeout, java.util.concurrent.TimeUnit timeUnit) throws Exception
{
Future<Value> result = objStorage.get(key, new ObjectAsyncCallbackImpl<Value>( waitObj), timeout, timeUnit);
synchronized ( waitObj) {
waitObj.wait();
}
System.out.println( "-----------success" + result.isDone());
Assert.assertTrue(result.isDone());
return result.get();
}
回调函数的实现:
public class ObjectAsyncCallbackImpl<T> implements DataCellAsyncCallback<T>
{
private static Logger logger = Logger.getLogger(ObjectAsyncCallbackImpl.class);
public Object waitObj;
public ObjectAsyncCallbackImpl(Object waitObj)
{
this. waitObj = waitObj;
}
@Override
public void onFailure(Throwable throwable)
{
logger.info(throwable.getMessage());
Assert.assertTrue(null == throwable);
}
@Override
public void onSuccess(T payload)
{
synchronized ( waitObj) {
waitObj.notify();
logger.debug("success........." );
}
}
}
TAsyncClientManager clientManager = new TAsyncClientManager(); TNonblockingSocket transport = new TNonblockingSocket("localhost", port, 500000); TJSONProtocol.Factory protocolFactory = new TJSONProtocol.Factory(); Hello.AsyncClient asycnClient = new Hello.AsyncClient( protocolFactory, clientManager, transport); MyCallback callback = new MyCallback(wait); asycnClient.helloString("libin", callback); synchronized (wait) { wait.wait(); } AsyncClient.helloString_call msg = callback.getResult(); System.out.println("================== async client msg = " + msg);
public class MyCallback implements AsyncMethodCallback<AsyncClient.helloString_call> { private helloString_call response = null; private Object wait; public MyCallback(Object wait) { this.wait = wait; } @Override public void onComplete(helloString_call response) { // TODO Auto-generated method stub System.out.println("onComplete"); try { synchronized (wait) { this.response = response; System.out.println(response.getResult()); wait.notify(); } } catch (TException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void onError(Exception e) { // TODO Auto-generated method stub System.out.println("error\t:" + e.getMessage()); } public helloString_call getResult() { // TODO Auto-generated method stub return response; } }
Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
五、以上规则对其它对象锁同样适用.
java中synchronized用法
打个比方:一个object就像一个大房子,大门永远打开。房子里有 很多房间(也就是方法)。
这些房间有上锁的(synchronized方法), 和不上锁之分(普通方法)。房门口放着一把钥匙(key),这把钥匙可以打开所有上锁的房间。
另外我把所有想调用该对象方法的线程比喻成想进入这房子某个 房间的人。所有的东西就这么多了,下面我们看看这些东西之间如何作用的。
在此我们先来明确一下我们的前提条件。该对象至少有一个synchronized方法,否则这个key还有啥意义。当然也就不会有我们的这个主题了。
一个人想进入某间上了锁的房间,他来到房子门口,看见钥匙在那儿(说明暂时还没有其他人要使用上锁的 房间)。于是他走上去拿到了钥匙
,并且按照自己 的计划使用那些房间。注意一点,他每次使用完一次上锁的房间后会马上把钥匙还回去。即使他要连续使用两间上锁的房间,
中间他也要把钥匙还回去,再取回来。
因此,普通情况下钥匙的使用原则是:“随用随借,用完即还。”
这时其他人可以不受限制的使用那些不上锁的房间,一个人用一间可以,两个人用一间也可以,没限制。但是如果当某个人想要进入上锁的房
间,他就要跑到大门口去看看了。有钥匙当然拿了就走,没有的话,就只能等了。
要是很多人在等这把钥匙,等钥匙还回来以后,谁会优先得到钥匙?Not guaranteed。象前面例子里那个想连续使用两个上锁房间的家伙,他
中间还钥匙的时候如果还有其他人在等钥匙,那么没有任何保证这家伙能再次拿到。 (JAVA规范在很多地方都明确说明不保证,象
Thread.sleep()休息后多久会返回运行,相同优先权的线程那个首先被执行,当要访问对象的锁被 释放后处于等待池的多个线程哪个会优先得
到,等等。我想最终的决定权是在JVM,之所以不保证,就是因为JVM在做出上述决定的时候,绝不是简简单单根据 一个条件来做出判断,而是
根据很多条。而由于判断条件太多,如果说出来可能会影响JAVA的推广,也可能是因为知识产权保护的原因吧。SUN给了个不保证 就混过去了
。无可厚非。但我相信这些不确定,并非完全不确定。因为计算机这东西本身就是按指令运行的。即使看起来很随机的现象,其实都是有规律
可寻。学过 计算机的都知道,计算机里随机数的学名是伪随机数,是人运用一定的方法写出来的,看上去随机罢了。另外,或许是因为要想弄
的确定太费事,也没多大意义,所 以不确定就不确定了吧。)
再来看看同步代码块。和同步方法有小小的不同。
1.从尺寸上讲,同步代码块比同步方法小。你可以把同步代码块看成是没上锁房间里的一块用带锁的屏风隔开的空间。
2.同步代码块还可以人为的指定获得某个其它对象的key。就像是指定用哪一把钥匙才能开这个屏风的锁,你可以用本房的钥匙;你也可以指定
用另一个房子的钥匙才能开,这样的话,你要跑到另一栋房子那儿把那个钥匙拿来,并用那个房子的钥匙来打开这个房子的带锁的屏风。
记住你获得的那另一栋房子的钥匙,并不影响其他人进入那栋房子没有锁的房间。
为什么要使用同步代码块呢?我想应该是这样的:首先对程序来讲同步的部分很影响运行效率,而一个方法通常是先创建一些局部变
量,再对这些变量做一些 操作,如运算,显示等等;而同步所覆盖的代码越多,对效率的影响就越严重。因此我们通常尽量缩小其影响范围。
如何做?同步代码块。我们只把一个方法中该同 步的地方同步,比如运算。
另外,同步代码块可以指定钥匙这一特点有个额外的好处,是可以在一定时期内霸占某个对象的key。还记得前面说过普通情况下钥
匙的使用原则吗。现在不是普通情况了。你所取得的那把钥匙不是永远不还,而是在退出同步代码块时才还。
还用前面那个想连续用两个上锁房间的家伙打比方。怎样才能在用完一间以后,继续使用另一间呢。用同步代码块吧。先创建另外
一个线程,做一个同步代码 块,把那个代码块的锁指向这个房子的钥匙。然后启动那个线程。只要你能在进入那个代码块时抓到这房子的钥匙
,你就可以一直保留到退出那个代码块。也就是说 你甚至可以对本房内所有上锁的房间遍历,甚至再sleep(10*60*1000),而房门口却还有
1000个线程在等这把钥匙呢。很过瘾吧。
在此对sleep()方法和钥匙的关联性讲一下。一个线程在拿到key后,且没有完成同步的内容时,如果被强制sleep()了,那key还一
直在 它那儿。直到它再次运行,做完所有同步内容,才会归还key。记住,那家伙只是干活干累了,去休息一下,他并没干完他要干的事。为
了避免别人进入那个房间 把里面搞的一团糟,即使在睡觉的时候他也要把那唯一的钥匙戴在身上。
最后,也许有人会问,为什么要一把钥匙通开,而不是一个钥匙一个门呢?我想这纯粹是因为复杂性问题。一个钥匙一个门当然更
安全,但是会牵扯好多问题。钥匙 的产生,保管,获得,归还等等。其复杂性有可能随同步方法的增加呈几何级数增加,严重影响效率。这也
算是一个权衡的问题吧。为了增加一点点安全性,导致效 率大大降低,是多么不可取啊。
搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程序。
还有一些技巧可以让我们对共享资源的同步访问更加安全:
1. 定义private 的instance变量+它的 get方法,而不要定义public/protected的instance变量。如果将变量定义为public,对象在外界可以
绕过同步方法的控制而直接取得它,并改动它。这也是JavaBean的标准实现方式之一。
2. 如果instance变量是一个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象
的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。 这个时候就需要将get方法也加上synchronized同步,并
且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了
相关推荐
异步调用是一种非阻塞的调用方式,调用方在调用过程中,不直接等待返回结果,而是执行其他任务,结果返回形式通常为回调函数。SYNC调用是指调用方在调用过程中,持续等待返回结果。Java中将异步调用转换为同步调用有...
本话题将深入探讨如何在Android中使用JNI进行多线程编程,并实现native方法对Java函数的回调。 1. **JNI基础知识**: - JNI是Java平台的一部分,为Java应用程序提供了与本地代码交互的能力。开发者可以通过JNI在...
有时,我们需要在JNI线程中执行一些耗时操作,并将结果回调到Java层。本文将深入探讨如何在Android的JNI线程中实现回调机制。 首先,我们需要了解Android线程的基本概念。主线程,也称为UI线程,负责处理用户界面的...
- **异步(Asynchronous)**:指程序无需等待某个操作完成就可以继续执行其他任务,当该操作完成后会通过回调、事件等方式通知调用者。这就好比你告诉朋友你要去吃饭了,然后你自己先去了,不管朋友什么时候到。 -...
同步回调的一个常见例子是在线程间通信,例如通过`synchronized`关键字或者`wait/notify`机制。异步回调常常与Java的并发库(如`ExecutorService`,`Future`,`CompletableFuture`等)结合,或者在网络编程中的`...
异步编程在JavaScript(通过回调函数、Promise和async/await)、Python的`asyncio`库,以及C#的`async/await`关键字中广泛应用。 "多线程实现打字练习"可能是一个利用多线程来提高用户交互体验的例子,其中,一个...
在JavaScript中,异步编程更为常见,因为它是单线程的环境,所有的I/O操作(如网络请求、文件读写)都是异步的,通过事件循环和回调函数来处理。JavaScript也提供了Promise和async/await等机制来更好地管理异步流程...
在Java编程语言中,同步(Synchronization)与异步(Asynchronization)是两个非常重要的概念,它们对于多线程处理和并发控制有着不可替代的作用。本文将深入探讨这两个概念的区别及其在Java中的具体应用。 #### 一...
异步则允许线程无序执行,通常伴随着回调或事件驱动模型,它提高了系统的响应速度,但可能导致结果的不确定性。 实验内容是创建一个银行账户系统,该系统支持多个用户同时进行存取款操作。为了确保账户余额的正确性...
3. **回调函数**:在任务完成后调用预定义的函数,常用于事件驱动编程。 4. **Lambda表达式和流API**:Java 8引入的特性,使异步编程更加简洁,可以与`CompletableFuture`结合使用。 5. **反应式编程**:如Reactor...
然而,异步编程可能会导致代码复杂性增加,因为需要处理回调地狱(Callback Hell)或使用Promise、CompletableFuture等高级特性来管理异步流程。Java 8引入了 CompletableFuture 类,使得异步编程变得更加灵活和易于...
3. **回调函数**:在异步操作完成后,可以指定一个回调函数,该函数将在主线程上运行,以便处理完成后的逻辑。 4. **IAsyncResult接口**:`BeginInvoke`方法返回一个实现了`IAsyncResult`接口的对象,它可以用来...
在Java多线程编程中,面试题常常涉及到线程的基本概念、同步与异步的区别、线程同步方法以及Java提供的并发工具类。下面我们将深入探讨这些知识点。 1. **线程间的协作**: - `sleep()` 和 `wait()` 的区别:`...
总结,Java中的异步调用通过多线程、Future、Callable、CompletableFuture、回调函数等机制实现,极大地提高了程序的并发性能和响应性。在实际开发中,结合Spring框架和消息队列,我们可以构建高效、可扩展的后端...
回调函数`Callback`可以用来通知主线程图片下载完成,然后在UI上显示。这样,即使在多个地方同时请求同一张图片,我们也只需要下载一次,大大提高了效率。 在`ImageUtilTest`文件中,我们可以编写单元测试,模拟...
六、异步编程和回调 1. 异步编程:非阻塞式I/O,允许线程在等待结果时执行其他任务,如Java的Future和CompletableFuture,JavaScript的Promise。 2. 回调函数:当异步操作完成时,调用预先注册的函数,处理结果或...
4. AsyncTask:Android提供的轻量级线程工具,适合短时间、频繁的任务,自动管理线程和回调到主线程更新UI。 5. IntentService:用于后台执行耗时任务,单线程,任务完成后自动停止服务。 三、线程同步与通信 1. ...