一:synchronized 隐形锁
属于排它锁。
1、synchronized 锁类使得多个对象有序的调用一个run方法
举例:
问题描述:火车站卖票系统,火车站有多个售票窗口,每张票都有自己的编号,不同的窗口同时卖票,不可以在不同的窗口卖出同一张票。
首先有一个票类:用来存储车票的信息。
public class Ticket {
private String tno;
public Ticket(String tno) {
this.tno=tno;
}
public String getTno() {
return tno;
}
public void setTno(String tno) {
this.tno = tno;
}
}
要有窗口类:用来售票。
public class Windows implements Runnable {
private LinkedList<Ticket> tickest=new LinkedList<>();//将窗口类和票类关联
public Windows(LinkedList<Ticket> tickest) {
this.tickest=tickest;
}
//run中使用任何锁都不会达到同步效果,因为有多个window对象
@Override
public void run() {
// TODO Auto-generated method stub
while(true) {
try {
shell(tickest);
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//卖票 此处必须是static方法,否则三个window,会调三个不同的run(),在run()中使用锁是无效的
synchronized public static void shell(LinkedList<Ticket> tickest) {
if(tickest.size()>0) {
Ticket t=tickest.removeLast();
System.out.println(Thread.currentThread().getId()+"卖了一张票"+t.getTno());
}
}
}
测试类:
假设有100张车票,用LinkedList的原因是底层实现为链表,删除时方便
public class Test {
public static void main(String[] args) {
LinkedList<Ticket> ts = new LinkedList<>();
for(int i=0;i<100;i++) {
Ticket t = new Ticket(Integer.toString(i));
ts.add(t);
}
new Thread(new Windows(ts)).start();
new Thread(new Windows(ts)).start();
new Thread(new Windows(ts)).start();
}
}
测试结果:
10卖了一张票99
11卖了一张票98
12卖了一张票97
12卖了一张票96
11卖了一张票95
10卖了一张票94
11卖了一张票93
12卖了一张票92
10卖了一张票91
12卖了一张票90
.
.
.
12卖了一张票3
11卖了一张票2
10卖了一张票1
12卖了一张票0
注意: 非static方法使用synchronized ,本质是给当前对象加锁
2、synchronized 俩把锁问题
问题描述:花园洋房有大门和屋门来个门,一群人想要进入屋子必须先进入大门,然后进入屋门,要求在进大门的时候不妨碍进屋门。
public class GradenHouse{
private Object obj1=new Object();
private Object obj2=new Object();
public void openDoor() {
synchronized(obj1) {
System.out.println(Thread.currentThread().getId()+"开大门");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getId()+"进大门");
}
}
public void openRoom() {
synchronized(obj2) {
System.out.println(Thread.currentThread().getId()+"。。。。。开屋门");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getId()+"。。。。。进屋门");
}
}
}
public class Test {
public static void main(String[] args) {
ExecutorService pool=Executors.newCachedThreadPool();
GradenHouse gh=new GradenHouse();
for(int i=0;i<100;i++) {
pool.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
gh.openDoor();
gh.openRoom();
}
});
}
}
}
执行结果:
10。。。。。开屋门
10。。。。。进屋门
109进大门
109。。。。。开屋门
108开大门
109。。。。。进屋门
108进大门
107开大门
108。。。。。开屋门
107进大门
108。。。。。进屋门
107。。。。。开屋门
106开大门
107。。。。。进屋门
.
.
.
二:ReentrantLock 重入锁
属于排它锁。
举例:还是上面那个换能源洋房问题。
public class GradenHouse{
private ReentrantLock doorLock;
private ReentrantLock roomLock;
public GradenHouse() {
doorLock=new ReentrantLock();
roomLock=new ReentrantLock();
}
/**
* 一次只能有一个人进入大门
*/
public void openDoor() {
try {
doorLock.lock();//获得锁。
System.out.println(Thread.currentThread().getId()+"开大门");
try {
Thread.sleep(200);
} catch (Exception e) {
// TODO: handle exception
}
System.out.println(Thread.currentThread().getId()+"进大门");
} finally {
doorLock.unlock();//释放锁
}
}
public void openRoom() {
try {
roomLock.lock();
System.out.println(Thread.currentThread().getId()+"开屋门");
try {
Thread.sleep(200);
} catch (Exception e) {
// TODO: handle exception
}
System.out.println(Thread.currentThread().getId()+"进屋门");
} finally {
roomLock.unlock();
}
}
}
public class Test {
public static void main(String[] args) {
ExecutorService pool=Executors.newCachedThreadPool();
GradenHouse gh=new GradenHouse();
for(int i=0;i<100;i++) {
pool.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
gh.openDoor();
gh.openRoom();
}
});
}
}
}
执行结果:
10开大门
10进大门
10开屋门
12开大门
10进屋门
12进大门
11开大门
12开屋门
12进屋门
11进大门
11开屋门
13开大门
13进大门
11进屋门
.
.
.
void lock() 获得锁。
void unlock() 尝试释放此锁。