tutorials sitehtml
单CPU,一次只能运行一个程序 -- 多任务,一次同时运行多个任务 (问题是每一个任务不能永远占有资源或者CPU,再也不使用资源或者CPU的程序须要释放掉本身的资源) -- 多线程,每一个任务都有多线程进行处理,每一个执行着的线程均可以当作是一个CPU。(问题是 每一个线程都执行相同的任务,所以同时读和写同一段内存,这会致使单线程不能出现的问题) 举个例子: 若是一个线程读了一块内存 同时发生了另外一个线程写到了这块内存。那么第一个线程读到的是什么? old value or the value just wriiten or a value mid between the two. 若是更多的线程同时写到了这个内存,第一个线程读到什么。 Therefore it is important as a developer to know how to take the right precautions - meaning learning to control how threads access shared resources like memory, files, databases etc. That is one of the topics this Java concurrency tutorial addresses.
多进程和多线程的区别?
本质的区别在于每一个进程拥有本身的一整套变量,而线程则共享数据。共享数据使线程之间的通讯比进程之间的通讯更有效。java
此外在有些操做系统中,与进程相比较,线程更加轻量级,建立,撤销一个线程比启动线程开销要小不少。web
JVM 的内存模型 能够分为调用栈,堆,方法区,寄存器,本地方法栈;其中主要组成是前二。
同一进程中的多条线程将共享该进程中的所有系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈
(call stack),本身的寄存器环境
(register context),本身的线程本地存储
(thread-local storage)安全
每个在JVM中运行的线程都有本身的调用栈call stack, 调用栈存储着该线程调用了哪些方法
以及这些方法的局部变量
。每一个栈只能查看本身的局部变量,没法查看其它栈的局部变量。服务器
Objects on the heap can be accessed by all threads that have a reference to the object. When a thread has access to an object, it can also get access to that object's member variables. If two threads call a method on the same object at the same time, they will both have access to the object's member variables, but each thread will have its
own copy
of the local variables.多线程
使用并发的好处:并发
* 更好的资源利用率 * 更精简的程序设计(一个线程负责读,一个线程负责写,一个线程只作一个功能,这样程序设计精简多了) * 更多响应的程序 (服务器监听线程,处理线程的例子)
使用并发的代价:app
* 设计更复杂 Code executed by multiple threads accessing shared data need special attention. Thread interaction is far from always simple. Errors arising from incorrect thread synchronization can be very hard to detect, reproduce and fix. * 上下文切换 When a CPU switches from executing one thread to executing another, the CPU needs to save the local data, program pointer etc. of the current thread, and load the local data, program pointer etc. of the next thread to execute. This switch is called a "context switch". * 消耗资源 CPU须要额外的空间时间去维护一个线程。
并发模型ide
start 和 run的区别说明ui
* start() 的做用是 启动一个新线程(操做系统级别,有一个native方法start0() 启动新线程),新线程会执行相应的run方法。 * run() 和普通的成员方法同样,能够被重复调用。 单独调用run() 会在当前线程中执行run() 并不会启动新线程
建立一个线程Thread thread = new Thread(); thread.start() 便可
可是这个线程没有执行任何代码段。
有两种方式能够指定哪段代码 一个线程会执行。
javapublic class MyThread extends Thread { public void run(){ System.out.println("MyThread running"); } }
To create and start the above thread you can do like this:
javaMyThread myThread = new MyThread(); myTread.start();
public class MyRunnable implements Runnable { public void run(){ System.out.println("MyRunnable running"); } }
To have the run() method executed by a thread, pass an instance of MyRunnable to a Thread in its constructor. Here is how that is done:
Thread thread = new Thread(new MyRunnable()); thread.start();
The problems arise when multiple threads access the same resources
.For instance the same memory (variables, arrays, or objects), systems (databases, web services etc.) or files. In fact, problems only arise if one or more of the threads write to these resources. It is safe to let multiple threads read the same resources, as long as the resources do not change.
The situation where two threads compete for the same resource, where the sequence in which the resource is accessed is significant, is called
race conditions
. A code section that leads to race conditions is called acritical section
. In the previous example the method add() is a critical section, leading to race conditions. Race conditions can be avoided by properthread synchronization
in critical sections.
Code that is safe to call by multiple threads simultanously is called
thread safe
.If a piece of code is thread safe, then it contains no race conditions
. Race condition only occur when multiple threads update shared resources. Therefore it is important to know what resources Java threads share when executing.
Java 不共享的资源有:
thread safe
.public void someMethod(){ long threadSafeInt = 0; threadSafeInt++; }
Java 共享的资源有:
好比以下的例子,由于localObject没有做为返回值返回,其余的线程获取不到这个对象的
javapublic void someMethod(){ LocalObject localObject = new LocalObject(); localObject.callMethod(); method2(localObject); } public void method2(LocalObject localObject){ localObject.setValue("value"); }
好比这个例子中,方法add就是线程不安全的(由于build是对象成员变量,多线程都对它同时操做)。
public class NotThreadSafe{ StringBuilder builder = new StringBuilder(); public add(String text){ this.builder.append(text); } }
若是两个线程同时调用同一个 NotThreadSafe 实例的 add() 方法就会引发race condition。好比:
NotThreadSafe sharedInstance = new NotThreadSafe(); new Thread(new MyRunnable(sharedInstance)).start(); // 线程1 new Thread(new MyRunnable(sharedInstance)).start(); // 线程2 public class MyRunnable implements Runnable{ NotThreadSafe instance = null; public MyRunnable(NotThreadSafe instance){ this.instance = instance; } public void run(){ this.instance.add("some text"); } }
然而若是两个线程在不一样的实例上面同时调用 add() 方法并不会引发静态条件。下面是稍微修改以后的例子:
new Thread(new MyRunnable(new NotThreadSafe())).start(); new Thread(new MyRunnable(new NotThreadSafe())).start();
如今这两个线程都有本身的 NotThreadSafe 实例,因此它们对 add 方法的调用并不会妨碍对方,这段代码没有竞态条件。因此即便一个对象不是线程安全的,仍能够找到一个方式来消除竞态条件。
可使用线程逃逸准则 Thread Control Escape Rule 来判断是否代码访问的资源是线程安全的。
若是一个资源在一个线程的控制下被建立、使用和销毁而且永远不会逃脱线程的控制,则该资源的使用是线程安全的。