`
ziwuzu
  • 浏览: 50264 次
  • 性别: Icon_minigender_1
  • 来自: 长春
社区版块
存档分类
最新评论

JAVA多线程概观

阅读更多

一.Java多线程模型

Java中,每个线程用一个Thread对象表示,每个线程有自己的执行流即方法调用栈和程序计数器。通过对Thread对象执行start操作,会让线程开始执行Threadrun方法,而run方法则是线程的执行流。

可以采用thread.sleep(),thread.interrupt(),thread.join()来控制单个线程的执行流。

 

二.Java多线程如何解决互斥和协同的问题

对于互斥问题,Java提供了锁机制,即synchronized关键字。另外对于单个变量的读写,java提供了volatile关键字,确保对单个变量的读和写是原子操作,即保证读和写是完整的,不会出错。

对于协同问题,Java提供了信号操作,即objectwait()notify()notifyAll()方法,即等待和唤醒策略。

 

三.Java多线程的其他问题

值得注意的就是可见性问题,由于java虚拟机里的内存模型是,每个线程有自己的一块工作空间,以方便加快程序的执行速度,这些工作空间里存储的是堆空间里的数据的缓存。由于每个线程都有自己对共享变量的一份缓存,从而导致出现共享变量的一致性问题。比如线程A对一个变量自增一,线程B也对一个变量自增一,如果两个线程并发的运行,除了确保每次只能有一个线程读取变量,修改变量,还必须确保,线程对这个变量进行的读和写是同步到公共的内存空间里去了。

对于共享变量的读和写的一致性问题,需要依赖对读和写操作确定happen-before关系来解决。就是如果要使一个写操作对其他线程的读操作可见,那么写操作的结果需要在读操作之前保存到共享空间中,并且读操作需要从共享空间中读取变量,不能采用自己工作空间的缓存。

如果对共享变量的操作没有happen-before关系,那么默认是不保证读操作能读到其他线程写的数据的。

Java规定的happen-before关系的操作

Each action in a thread happens-before every action in that thread that comes later in the program's order.

An unlock (synchronized block or method exit) of a monitor happens-before every subsequent lock (synchronized block or method entry) of that same monitor. And because the happens-before relation is transitive, all actions of a thread prior to unlocking happen-before all actions subsequent to any thread locking that monitor.

A write to a volatile field happens-before every subsequent read of that same field. Writes and reads of volatile fields have similar memory consistency effects as entering and exiting monitors, but do not entail mutual exclusion locking.

A call to start on a thread happens-before any action in the started thread.

All actions in a thread happen-before any other thread successfully returns from a join on that thread.

高级同步方案中的happen-before关系

Actions in a thread prior to placing an object into any concurrent collection happen-before actions subsequent to the access or removal of that element from the collection in another thread.

Actions in a thread prior to the submission of a Runnable to an Executor happen-before its execution begins. Similarly for Callables submitted to an ExecutorService.

Actions taken by the asynchronous computation represented by a Future happen-before actions subsequent to the retrieval of the result via Future.get() in another thread.

Actions prior to "releasing" synchronizer methods such as Lock.unlockSemaphore.release, and CountDownLatch.countDown happen-before actions subsequent to a successful "acquiring" method such asLock.lockSemaphore.acquireCondition.await, and CountDownLatch.await on the same synchronizer object in another thread.

For each pair of threads that successfully exchange objects via an Exchanger, actions prior to the exchange() in each thread happen-before those subsequent to the corresponding exchange() in another thread.

Actions prior to calling CyclicBarrier.await and Phaser.awaitAdvance (as well as its variants) happen-before actions performed by the barrier action, and actions performed by the barrier action happen-beforeactions subsequent to a successful return from the corresponding await in other threads.

 

四.Java多线程提供的高级解决方案有哪些

Lock,代替synchronized,wait,notify,notifyall

原子操作类AtomicInteger,AtomicLong,原理是非阻塞锁,实现单个对象的原子操作。

同步容器类ConcurrentHashMap,BlockedQueue,CopyOnWriteArray,对容器的元素操作进行锁操作。

线程控制框架Excuter,ExcuterService,ScheduleExcuterService提供线程池,线程创建功能。

 

五.Java多线程的指令重排序问题

指令重排问题:其实不用太过于担心,因为java在单个线程内部是不可能随便将指令进行乱序执行的,因为首先它要保证排序后的结果和代码的正常执行流程是一样的。比如先有一个system.out.println(1);再有一个system.out.println(2);在单个线程中,结果一定是先输出1再输出2,不会是先21。想想,如果这都不能操作,那我们还能信任编译器吗?所以jvm只敢在那些不影响程序外部表现的地方进行指令重排,而且需要保证不出错,如果真出错了,这个概率较小,计算机本身都有可能出错。

其实关注指令重排问题,是由于之前深入java虚拟机中,举的例子,说多线程操作共享变量,然后结果不一。原因很简单,在线程内部结果是一致的。只是涉及到了其他线程的时候,如果不对共享变量进行同步,会有两个问题,一个是可见性问题,二个是指令重排。而且java中提供的synchronized,volitale,ReentrantLock等锁的机制已经确保可见性和指令重排不会造成影响,所以不用考虑指令重排,只要考虑可见性即可。指令重排不需要我们知道,它本来就是jvm自己内部自己优化的东西,如果指令重排后程序出错了,这个是编译器的问题,我想它不太可能出这样的问题。

所以不用看指令重排了,搞定可见性就可以了。

可以参看java的官网上关于同步的教程,指令重排的问题根本没有提及,只提到了可见性,如果指令重排会导致程序出错,不合常理。

 

附录:

        一.Thread6种状态

l  NEW

Thread state for a thread which has not yet started.

l  RUNNABLE

Thread state for a runnable thread. A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.

l  WAITING

         Thread state for a waiting thread. A thread is in the waiting state due to calling one of the following methods:

    Object.wait with no timeout

   Thread.join with no timeout

   LockSupport.park

A thread in the waiting state is waiting for another thread to perform a particular action. For example, a thread that has called Object.wait() on an object is waiting for another thread to call Object.notify() or Object.notifyAll() on that object. A thread that has called Thread.join() is waiting for a specified thread to terminate.

l  BLOCKED

Thread state for a thread blocked waiting for a monitor lock. A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling Object.wait.

l  TIME-WAITING

Thread state for a waiting thread with a specified waiting time. A thread is in the timed waiting state due to calling one of the following methods with a specified positive waiting time:

l  TERNINATED

Thread state for a terminated thread. The thread has completed execution.

 

二.  重要

java官方多线程教程:http://docs.oracle.com/javase/tutorial/essential/concurrency/index.html

java7的api文档:http://docs.oracle.com/javase/7/docs/api/

 

分享到:
评论
1 楼 ziwuzu 2013-06-15  
指令重排这个我不确定了,可能需要再看看JAVA语言或虚拟机规范,之前在并发编程网上看到关于DCL的讨论,上面描述了构造函数没有执行完毕就被别人看见的事情,但我在实验中并没有发现这种现象,http://ifeve.com/jmm-faq-dcl/,上面有两篇文章是JAVA多线程的设计者的,需要仔细看看,来了解指令重排的问题

相关推荐

Global site tag (gtag.js) - Google Analytics