串行和并行:
串行:一个线程在处理操作
并行:多个线程在处理同一个操作
什么叫做并发编程:
在多线程环境下,应用程序的执行
并发编程的目的:充分运用到资源,提高程序的效率
什么情况下用到并发编程:
1.在线程阻塞时,导致应用程序停止
2.处理任务时间过长时,可以创建子任务,来进行分段处理
3.间断任务执行
一.并发编程中待解决的问题
1.并发编程中频繁上下文切换的问题
频繁上下文切换,可能会带来一定的性能开销
2.如何减少上下文性能开销:
2.1.无锁并发编程
2.2.CAS
2.3.使用最少线程数量
2.4.协程:在单线程环境下进行多任务的调度,可以在多任务之间进行任务切换
3.并发编程中死锁问题
3.1什么是死锁
死锁是指多个进程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。
例如,在某一个计算机系统中只有一台打印机和一台输入 设备,进程P1正占用输入设备,同时又提出使用打印机的请求,但此时打印机正被进程P2 所占用,而P2在未释放打印机之前,又提出请求使用正被P1占用着的输入设备
这样两个进程相互无休止地等待下去,均无法继续执行,此时两个进程陷入死锁状态。
例如下面的案例
package com.wish;
public class SiSuo {
//资源
private static final Object HAIR_A=new Object();
private static final Object HAIR_B=new Object();
public static void main(String[] args) {
//进程P1
new Thread(()->{
//我在使用输入设备
synchronized (HAIR_A){
System.out.println("我在使用输入设备,提出使用打印机的请求");
//延迟时间
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//提出使用打印机的请求
synchronized (HAIR_B){
System.out.println("进程P1使用打印机");
}
}
}).start();
//进程P2
new Thread(()->{
//我在使用打印机
synchronized (HAIR_B){
System.out.println("我在使用打印机,提出使用输入设备的请求");
//延迟时间
try {
Thread.sleep(100); //当前线程休眠,让渡CPU资源
} catch (InterruptedException e) {
e.printStackTrace();
}
//提出使用输入设备的请求
synchronized (HAIR_A){
System.out.println("进程P2使用输入设备");
}
}
}).start();
}
}
结果:就是双方互相占有进程没有停止一直耗着

3.2死锁产生的原因
3.2.1.系统资源的竞争导致系统资源不足,以及资源分配不当,导致死锁。
3.2.2.进程在运行过程中,请求和释放资源的顺序不当,会导致死锁。
3.3死锁的四个必要条件
互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某 资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)。
循环等待条件: 若干进程间形成首尾相接循环等待资源的关系
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
3.4如何预防死锁问题
3.4.1.破坏请求和保持条件:在申请资源时,一次性将资源都申请到
3.4.2.破坏不可占用条件:抢占资源如何不满足,那就释放所有资源,以后如果再需要则再次申请即可
3.4.3.破坏循环等待条件
4.线程安全问题
多个线程同时操作同一个资源,可能会造成资源数据不安全问题
列如如下代码
package com.wish;
import java.util.concurrent.CountDownLatch;
public class ThreadTest {
//资源
private static int num=0;
//计算线程数量
private static CountDownLatch countDownLatch=new CountDownLatch(10);
//对资源进行操作
public static void inCreate(){
num++;
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0 ; i < 10 ; i++ ){
new Thread(()->{
for (int j = 0 ; j < 100; j++){
inCreate();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//每一个线程执行完毕,让计数-1
countDownLatch.countDown();
}).start();
}
//等待计数器为0或者小于0执行await下面代码
countDownLatch.await();
System.out.println(num);
}
}
结果:它结果应该是1000但是它的结果却是681,就是应有许多个线程对它进行操作,但是互相都不知道别的线程的计算情况

解决线程不安全问题:
1.ReentrantLock对‘对资源的操作这一步骤’上一把锁,在执行完后在把锁释放掉
package com.wish;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadTest {
//资源
private static int num=0;
//计算线程数量
private static CountDownLatch countDownLatch=new CountDownLatch(10);
private static ReentrantLock reentrantLock = new ReentrantLock();
//对资源进行操作
public static void inCreate(){
//上锁
reentrantLock.lock();
num++;
reentrantLock.unlock();
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0 ; i < 10 ; i++ ){
new Thread(()->{
for (int j = 0 ; j < 100; j++){
inCreate();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//每一个线程执行完毕,让计数-1
countDownLatch.countDown();
}).start();
}
//等待计数器为0或者小于0执行await下面代码
countDownLatch.await();
System.out.println(num);
}
}

2.使用synchronized关键字,对操作资源的方法进行修饰
package com.wish;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadTest {
//资源
private static int num=0;
//计算线程数量
private static CountDownLatch countDownLatch=new CountDownLatch(10);
private static ReentrantLock reentrantLock = new ReentrantLock();
//对资源进行操作
public static synchronized void inCreate(){
//上锁
num++;
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0 ; i < 10 ; i++ ){
new Thread(()->{
for (int j = 0 ; j < 100; j++){
inCreate();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//每一个线程执行完毕,让计数-1
countDownLatch.countDown();
}).start();
}
//等待计数器为0或者小于0执行await下面代码
countDownLatch.await();
System.out.println(num);
}
}

浙公网安备 33010602011771号