第1章 走入并行世界
并发(Concurrency)和并行(Parallenlism)并发:偏重多个任务交替执行,二多个任务之间有可能还是串行的。即一会儿运行任务A,一会儿运行任务B,系统会不停滴在两者间切换。
并行:真正意义上的“同时执行”。
临界区:用来表示一种公共资源或者共享数据,可以被多个线程使用,但是每一次只能有一个线程使用它。一旦临界区被占用,其他线程就不能使用这个资源了。
阻塞和非阻塞。一个线程占用了临界区,其他线程就必须等待,从而导致其他线程挂起。这就是阻塞。
非阻塞:没有一个线程可以妨碍其他线程执行,所有的线程都会被尝试不断前向执行。
死锁:线程之前彼此相互占用对方资源而没有释放。
饥饿:某一个或者多个线程因为种种原因无法获得所需要的资源,导致一直无法执行。
活锁:资源不断在两个线程中跳动,而没有一个线程可以同时拿到所有资源而正常执行。
并发级别:阻塞,无饥饿,无障碍,无锁,无等待。
Java的内存模型(JMM):
原子性:指一个操作是不可中断的,即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。eg。int i= 2.(基本类型赋值)
可见性:当一个线程修改了某一个共享变量的值,其他线程是否能够立即知道这个修改。
有序性:习惯地认为代码执行是从先往后依次执行的,从一个线程内而言,确实会是这样的,但是在并发情况下,就不是这样的啦。
第2章 Java并行程序基础
新建线程:
Thread t1 = new Thread();
t1.start();
区别 Thread t2 = new Thread();
t2.run();
t1.start() 方法就会新建一个线程让这个线程执行run方法。而t2.run()方法不会新创建一个线程,只是在当前线程中,串行执行run()方法的代码。
停止线程:不能调用stop()方法,而是需要由我们自行决定线程何时退出。
public void run() {
while(1) {
if(stopme){
System.out.printIn("exit by stop");
break;
}
synchronized(u) {
.....线程操作。
}
}
}
初学者常见的问题:错误的加锁
错误方式:
politic static integer i = 0;
eg。 for(int j =0;j<100000000;j++) {
synchronized(j) {
j++;
}
}
正确方式:
eg。 for(int j =0;j<100000000;j++) {
synchronized(instance) {
j++;
}
}
这里还有申请锁,释放锁频繁(即是锁的粗化)。
synchronized(instance) {
for(int j =0;j<100000000;j++) {
j++;
}
}
第3章 JDK 并发包
信号量(Sempaphore)是对锁的扩展,无论是内部锁(synchronized)还是重入锁(ReentrantLock)一次都只允许一个线程访问一个资源,而信号量可以指定多个线程,同时访问一个资源。
第4章 锁的优化和注意事项
锁粗化: 当有一连串连续地对同一锁不断进行请求和释放的操作时,Java虚拟机会把所有的锁操作合成对锁的一次请求,从而减少对锁的请求同步次数。
锁偏向:是一种针对加锁操作的优化手段,如果一个线程获得了锁,那么锁就进入偏向模式,当这个线程再次请求锁时,无须在做任何同步操作,这样可以节省大量有关锁申请的操作。
网友评论