21天养成好习惯_第十六天
今天学习synchronized关键字的问题
参考资料: 深入理解Java并发之synchronized实现原理
重要的知识点: (要求对关键字的有很准确的理解)
- 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
- 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁
- 修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁
因为作者确实总结得很好, 强烈建议看原文
参考资料的文章摘要
“synchronized修饰的是实例方法increase,在这样的情况下,当前线程的锁便是实例对象instance”
“访问静态 synchronized 方法占用的锁是当前类的class对象,而访问非静态 synchronized 方法占用的锁是当前实例对象锁”
“将synchronized作用于一个给定的实例对象instance,即当前实例对象就是锁对象,每次当线程进入synchronized包裹的代码块时就会要求当前线程持有instance实例对象锁,如果当前有其他线程正持有该对象锁,那么新到的线程就必须等待,这样也就保证了每次只有一个线程执行i++;操作”
死锁
package Net_Study.Syn;
public class DeadLock {
public static void main(String[] args) {
girl g1 = new girl(0, "灰姑凉");
girl g2 = new girl(1, "白雪公主");
//要想避免死锁,那就只需要"别使用嵌套锁"
new Thread(g1).start();
new Thread(g2).start();
}
}
class Lipstick{
}
class mirror{
}
class girl extends Thread{
static Lipstick lipstick = new Lipstick();
static mirror mirror = new mirror();
int choice;
String girlName;
girl(int choice,String girlName){
this.choice = choice;
this.girlName = girlName;
}
@Override
public void run() {
try {
makeup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void makeup() throws InterruptedException {
if (0 == choice){
synchronized (lipstick){ //必须是static对象(类的元素)
System.out.println(Thread.currentThread().getName() +" 获得lipstick的锁");
sleep(100);
}
synchronized (mirror){
System.out.println(Thread.currentThread().getName() + " 获得mirror的锁");
}
}else{
synchronized (mirror){
System.out.println(Thread.currentThread().getName() + " 获得mirror的锁");
sleep(200);
}
synchronized (lipstick){
System.out.println(Thread.currentThread().getName() + " 获得lipstick的锁");
}
}
}
}
运行结果:
个人心得:
产生死锁的隐患是: 嵌套得使用锁机制
要想避免死锁 就不写嵌套的锁
Java的lock关键字
package Net_Study.Syn;
import java.util.concurrent.locks.ReentrantLock;
public class TestLock {
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(ticket).start();
new Thread(ticket).start();
new Thread(ticket).start();
new Thread(ticket).start();
//99.999% 不会出错
}
}
class Ticket implements Runnable{
int ticketNum = 10;
//定义lock锁
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
//手动加锁
lock.lock();
if (ticketNum>0){
Thread.sleep(100);
System.out.println(ticketNum--);
}else{
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//手动解锁
lock.unlock();
}
}
}
}
运行结果:
小总结:
Java 的lock关键字的使用类似于C++的lock使用
但Java可以利用try{}finally{} 避免忘记lock.unlock()的情况