java 大道至简--多线程(9)
内容目录:
锁
正文
前面的文章我们了解了线程的通信,线程的并发问题,可能大家注意到了一个问题,就是我们基本上都是用到了一个关键字,synchronized 其实在第一篇的博文中我们已经做了个最简单的了解,所以在这里对于锁的定义我就不做过多的解释了,本章我们就锁的应用做进一步的探讨和较为深入的研究
我门从以下三个方面进行探讨:
1、什么情况使用锁
2、怎么用
2.1 synchronized关键字
2.2 Lock接口
3、锁的常见问题和解决方案
1、什么情况使用锁
通过多线程之间的通信,并发编程我们已经大致了解了我们什么时候要采用锁,总结就是一句话,在使用多线程的时候我们就要用到锁,你多线程用的好不好更多的还是看你对于锁的理解和使用到不到位
2、怎样使用锁
在使用多线程的时候我们肯定会使用到锁,那么具体怎么来使用锁呢,我们再来简单的提一句锁的作用,就是为了满足内存一致性,我们将要操作的对象进行特殊处理,以此来告诉虚拟机,这个对象是同步的,即要检查内存一致,同时保护这个对象,防止其他线程对其操作,直到当前线程操作结束后,才能再次修改,那么这个特殊处理就是我们的锁,最常见也最方便的就是我们的关键字 sychronized,还有java.util.concurrent.Locks接口
3、锁的常见问题和解决方案
死锁--多个线程彼此等待对方结束而被永久阻塞的情况
参看以下例子
package com.hello.test;
public class HelloWorld{
static Object lock1 = "a";
static Object lock2 = "b";
public static void main(String[] args) {
ThreadDemo1 thread1 = new ThreadDemo1();
ThreadDemo2 thread2 = new ThreadDemo2();
Thread thread3 = new Thread(thread1);
Thread thread4 = new Thread(thread2);
thread3.start();
thread4.start();
}
private static class ThreadDemo1 implements Runnable{
@Override
public void run() {
synchronized(lock1) {
System.out.println("Thread 1: Holding lock 1...");
try {
Thread.sleep(5*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 1: Holding lock 1...");
synchronized(lock2) {
System.out.println("Thread 1: Holding lock 1 & 2");
}
}
}
}
private static class ThreadDemo2 implements Runnable{
@Override
public void run() {
synchronized(lock2) {
System.out.println("Thread 2: Holding lock 2...");
try {
Thread.sleep(5*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 2: Holding lock 1...");
synchronized(lock1) {
System.out.println("Thread 2: Holding lock 1 & 2");
}
}
}
}
}
结果:
Thread 1: Holding lock 1...
Thread 2: Holding lock 2...
Thread 1: Holding lock 1...
Thread 2: Holding lock 1...
此时程序还在运行但是后面的System.out.println("Thread 1: Holding lock 1 & 2");
System.out.println("Thread 2: Holding lock 1 & 2");
并没有执行,程序“卡住”了,
我们现在来分析一下为什么会“卡住”。
1、程序启动的时候我们同时启动了 ThreadDemo1 和ThreadDemo2 两个线程,并且会同时执行run()函数
2、synchronized的用法
synchronized在java语言中是一个关键字,意思是同步,它可以用来修饰函数(方法),表示整个函数都是同步的,也可以在函数中单独使用,格式为:
synchronized(Object){函数体} ,此结构通常称为同步代码块,类似静态代码块,表示当前线程获的对象(object)时,执行具体的函数体,synchronized会自动释放资源(锁),以供其他线程调用
3、ThreadDemo1首先获取lock1,ThreadDemo2首先获取lock2
4、ThreadDemo1执行第二个synchronized时试图获取lock2,但此时lock2已经被ThreadDemo2获取了,ThreadDemo1只好等待lock2被释放
5、ThreadDemo2执行第二个synchronized时试图获取lock1,但此时lock1已经被ThreadDemo1获取了,ThreadDemo2只好等待lock1被释放
6、就这样两个线程相互等待对方释放资源,就像拔河比赛,我等你先放手,你等我先放手,就这样相互纠缠直到永远
以上是分析造成死锁的原因,因为篇幅有限,所以下一篇我们来介绍如何解决这个死锁问题,