并发编程情况下几个相应问题简介
1.并发编程的挑战之死锁
死锁是两个或更多线程阻塞着等待其它处于死锁状态的线程所持有的锁。死锁通常发生在多个线程同时但以不同的顺序请求同一组锁的时候。
例如,如果线程1锁住了A,然后尝试对B进行加锁,同时线程2已经锁住了B,接着尝试对A进行加锁,这时死锁就发生了。线程1永远得不到B,线程2也永远得不到A,并且它们永远也不会知道发生了这样的事情。为了得到彼此的对象(A和B),它们将永远阻塞下去。这种情况就是一个死锁。
举个例子:A和B打架,两人都想抓住对方的头发,于是我们可以依此编写如下的程序:
/**
* 死锁
*/
public class DeadLockDemo {
private static final Object HAIR_A = new Object();
private static final Object HAIR_B = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (HAIR_A) {
try {
Thread.sleep(50L);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (HAIR_B) {
System.out.println("A成功抓住B的头发");
}
}
}).start();
new Thread(() -> {
synchronized (HAIR_B) {
synchronized (HAIR_A) {
System.out.println("B成功抓住A的头发");
}
}
}).start();
}
}
这个时候由于A和B都想要获取对方的锁,而双方都紧握不放,导致谁也抓不到谁,最终一直僵持下去,造成死锁的发生,这个时候我们可以用监视器查相应的死锁状况:
2.并发编程的挑战之线程安全
线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据
下面我们来看一个例子,采取10个线程对num进行++的操作,此时会发现每次得到的结果都不一样;这个就是线程不安全造成的结果:
package xianchengxuexi;
import java.util.concurrent.CountDownLatch;
/**
* 线程不安全操作
*/
public class UnSafeThread {
private static int num = 0;
private static CountDownLatch countDownLatch =new CountDownLatch(10);
/**
* 每次调用对num进行++的操作
*
*/
public static void increment(){
num++;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
for (int j = 0; j <100 ; j++) {
increment();
try {
Thread.sleep(10L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//在每个线程只想完后调用cutdown
countDownLatch.countDown();
}).start();
}
while (true){
if(countDownLatch.getCount()==0){
break;
}
}
System.out.println(num);
}
}
此结果产生的原因用简图描述如下,就是在线程1睡眠的过程中,第二个线程进行了操作,但是拿到的结果仍然是未更新的值,也就是脏数据,这个进行操作就没有同步,造成线程不安全:
3.并发编程的挑战之资源挑战
- 硬件资源
- 服务器: 1m 本机:2m
- 带宽的上传/下载速度、硬盘读写速度和CPU的处理速度。
- 软件资源
- 数据库连接 500个连接 1000个线程查询 并不会因此而加快 socket