Parallelism vs. Concurrency
Parallelism: 指两个或两个以上事件或活动在同一时刻发生,并行性使多个程序同一时刻可在不同CPU上同时执行.并行的行为是真正的同时执行,在多核或多个机器上,并且并行是无状态的.
Concurrency: 指两个或两个以上的事件或活动在同一时间间隔内发生。并发的实质是一个物理CPU(也可以多个物理CPU) 在若干道程序之间多路复用,并发性是对有限物理资源强制行使多用户共享以提高效率。
并行是物理上同时发生,并发是逻辑上同时发生.系统中有多个任务同时存在即为并发,系统中有多个任务同时执行则为并发.并发是并行的子集.如果在单核CPU上,只能存在并发而不可能存在并行.
状态共享式并发
首先定义一个简单的User类:
public static class User {
private String first = "";
private String last = "";
public String getFirstName() {
return this.first;
}
public void setFirstName(String s) {
this.first = s;
}
public String getLastName() {
return this.last;
}
public void setLastName(String s) {
this.last = s;
}
}
让这个类支持并发,不允许两个不同的线程同时修改属性,因此增加同步属性:
public static class User {
private String first = "";
private String last = "";
synchronized public String getFirstName() {
return this.first;
}
synchronized public void setFirstName(String s) {
this.first = s;
}
synchronized public String getLastName() {
return this.last;
}
synchronized public void setLastName(String s) {
this.last = s;
}
}
如果对属性字段使用”volatile”的话效果会不会更好?
public static class User {
private volatile String first = "";
private volatile String last = "";
public String getFirstName() {
return this.first;
}
public void setFirstName(String s) {
this.first = s;
}
public String getLastName() {
return this.last;
}
public void setLastName(String s) {
this.last = s;
}
}
但是当你在并发程序中调用这段代码的时候:
user.setFirstName("Spider");
user.setFirstName("Green");
user.setLastName("Man");
user.setLastName("Lantern");
System.out.println(user.getFirstName() + " " + user.getLastName());
你会发现你得到的结果是”Spider Lantern”,这就是真正的问题所在.解决这种问题的办法:
import java.util.concurrent.locks.ReentrantLock;
public static class User {
private ReentrantLock lock = new ReentrantLock();
private String first = "";
private String last = "";
public void lock() {
lock.lock();
}
public void unlock() {
lock.unlock();
}
public String getFirstName() {
return this.first;
}
public void setFirstName(String s) {
try { lock();
this.first = s;
} finally {
unlock(); }
}
public String getLastName() {
return this.last;
}
public void setLastName(String s) {
try { lock();
this.last = s;
} finally {
unlock();
}
}
}
整个实现都是在围绕”并发锁”,使用的时候:
try {
user.lock();
System.out.println(user.getFirstName() + " " + user.getLastName());
} finally {
user.unlock();
}
这样就很好了解决了上面的问题,但是,如果遇到这样的使用情况:
// Thread 1
user.setFirstName("Green");
// Thread 2
try {
user.lock();
System.out.println(user.getFirstName() + " " + user.getLastName());
} finally {
user.unlock();
}
// Thread 1
user.setLastName("Lantern");
同样的错误又发生了.