一、概念
Lock类是java.util.concurrent.locks下,可以和synchronized实现同样功能的线程锁。二者区别:
1.Sychronized:隐式锁
可以锁:(1)同步代码块;(2)同步方法
2.Lock:是显示锁
注意:需要通过lock.lock()上锁,并且必须在finally内通过lock.unlock方法释放锁。
二、lock解决实例
1.出现多线程共享变量访问问题
package com.algorithm.learn.test.JUC;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by Administrator on 2020/1/16.
*/
public class TestLock {
public static void main(String[] args) {
Ticket ticket=new Ticket();
new Thread(ticket,"1号窗口").start();
new Thread(ticket,"2号窗口").start();
new Thread(ticket,"3号窗口").start();
}
}
class Ticket implements Runnable{
private int tick=100;
@Override
public void run() {
while (true){
if(tick>0){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"完成售票,余票为:"+ --tick);
}
}
}
}
结果:
...
1号窗口完成售票,余票为:6
2号窗口完成售票,余票为:5
3号窗口完成售票,余票为:6
3号窗口完成售票,余票为:4
2号窗口完成售票,余票为:3
1号窗口完成售票,余票为:2
3号窗口完成售票,余票为:0
2号窗口完成售票,余票为:1
1号窗口完成售票,余票为:-1
2.添加lock解决
package com.algorithm.learn.test.JUC;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by Administrator on 2020/1/16.
*/
public class TestLock {
public static void main(String[] args) {
Ticket ticket=new Ticket();
new Thread(ticket,"1号窗口").start();
new Thread(ticket,"2号窗口").start();
new Thread(ticket,"3号窗口").start();
}
}
class Ticket implements Runnable{
private int tick=100;
private Lock lock=new ReentrantLock();
@Override
public void run() {
while (true){
//1.上锁
lock.lock();
try {
if(tick>0){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"完成售票,余票为:"+ --tick);
}
}finally {
//3.解锁:一定在finally里
lock.unlock();
}
}
}
// @Override
// public void run() {
// while (true){
//
// if(tick>0){
// try {
// Thread.sleep(200);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName()+"完成售票,余票为:"+ --tick);
// }
//
// }
// }
}
结果:
...
3号窗口完成售票,余票为:6
1号窗口完成售票,余票为:5
2号窗口完成售票,余票为:4
2号窗口完成售票,余票为:3
3号窗口完成售票,余票为:2
3号窗口完成售票,余票为:1
1号窗口完成售票,余票为:0
3.生产者消费者实例(等待唤醒)
(1)synchronized 实现生产者和消费者实例,有虚假唤醒
package com.algorithm.learn.test.JUC;
/**
* Created by Administrator on 2020/1/16.
*/
public class TestProductorAndConsumer {
public static void main(String[] args) {
Clerk clerk=new Clerk();
Producer producer=new Producer(clerk);
Consumer consumer=new Consumer(clerk);
new Thread(producer,"生产者A").start();
new Thread(consumer,"消费者B").start();
}
}
/**
* 店员
*/
class Clerk{
private int product=0;
//进货
public synchronized void get(){
if(product>=10){
System.out.println("产品已满!");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
System.out.println(Thread.currentThread().getName()+":"+ ++product);
this.notifyAll();
}
}
//卖货
public synchronized void sale(){
if(product<=0){
System.out.println("产品已没有了!");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
System.out.println(Thread.currentThread().getName()+":"+ --product);
this.notifyAll();
}
}
}
/**
* 生产者
*/
class Producer implements Runnable{
private Clerk clerk;
public Producer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
clerk.get();
}
}
}
/**
* 消费者
*/
class Consumer implements Runnable{
private Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
clerk.sale();
}
}
}
结果:
生产者A:1
生产者A:2
生产者A:3
生产者A:4
生产者A:5
生产者A:6
生产者A:7
生产者A:8
生产者A:9
生产者A:10
产品已满!
消费者B:9
消费者B:8
消费者B:7
消费者B:6
消费者B:5
消费者B:4
消费者B:3
消费者B:2
消费者B:1
消费者B:0
产品已没有了!
生产者A:1
生产者A:2
生产者A:3
生产者A:4
生产者A:5
生产者A:6
生产者A:7
生产者A:8
生产者A:9
消费者B:8
消费者B:7
消费者B:6
消费者B:5
消费者B:4
消费者B:3
消费者B:2
消费者B:1
消费者B:0
(2)synchronized解决虚假唤醒(使用while替换if)
package com.algorithm.learn.test.JUC;
/**
* Created by Administrator on 2020/1/16.
*/
public class TestProductorAndConsumer {
public static void main(String[] args) {
Clerk clerk=new Clerk();
Producer producer=new Producer(clerk);
Consumer consumer=new Consumer(clerk);
new Thread(producer,"生产者A").start();
new Thread(consumer,"消费者B").start();
new Thread(producer,"生产者C").start();
new Thread(consumer,"消费者D").start();
}
}
/**
* 店员
*/
class Clerk{
private int product=0;
//进货
public synchronized void get(){
while(product>=1){
System.out.println("产品已满!");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//else{
// System.out.println(Thread.currentThread().getName()+":"+ ++product);
// this.notifyAll();
// }
System.out.println(Thread.currentThread().getName()+":"+ ++product);
this.notifyAll();
}
//卖货
public synchronized void sale(){
while(product<=0){
System.out.println("缺货!");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// else {
// System.out.println(Thread.currentThread().getName()+":"+ --product);
// this.notifyAll();
// }
System.out.println(Thread.currentThread().getName()+":"+ --product);
this.notifyAll();
}
}
/**
* 生产者
*/
class Producer implements Runnable{
private Clerk clerk;
public Producer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
//添加延迟
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.get();
}
}
}
/**
* 消费者
*/
class Consumer implements Runnable{
private Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//添加延迟
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.sale();
}
}
}
结果:
生产者A:1
消费者D:0
生产者C:1
消费者B:0
生产者A:1
消费者D:0
生产者C:1
消费者B:0
缺货!
生产者C:1
消费者B:0
缺货!
生产者A:1
消费者D:0
缺货!
生产者C:1
消费者B:0
缺货!
生产者A:1
消费者D:0
缺货!
生产者C:1
消费者B:0
缺货!
生产者A:1
消费者D:0
生产者A:1
消费者D:0
缺货!
生产者C:1
消费者B:0
生产者C:1
消费者B:0
缺货!
生产者A:1
消费者D:0
生产者C:1
消费者B:0
缺货!
生产者A:1
消费者D:0
生产者C:1
消费者B:0
缺货!
生产者A:1
消费者D:0
生产者C:1
消费者B:0
生产者A:1
消费者D:0
缺货!
缺货!
(3)Lock实现生产者和消费者实例
Condition对象中,await、signal和signalAll分别对应Synchronized中wait、notify和notifyAll方法。
package com.algorithm.learn.test.JUC;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by Administrator on 2020/1/16.
*/
public class TestProductorAndConsumer {
public static void main(String[] args) {
Clerk clerk=new Clerk();
Producer producer=new Producer(clerk);
Consumer consumer=new Consumer(clerk);
new Thread(producer,"生产者A").start();
new Thread(consumer,"消费者B").start();
new Thread(producer,"生产者C").start();
new Thread(consumer,"消费者D").start();
}
}
/**
* 店员
*/
class Clerk{
private int product=0;
private Lock lock=new ReentrantLock();
private Condition condition=lock.newCondition();
//进货
public void get(){
lock.lock();
try {
while(product>=1){ //为了避免虚假唤醒问题,应该总是使用在循环中
System.out.println("产品已满!");
try {
// this.wait();
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//else{
// System.out.println(Thread.currentThread().getName()+":"+ ++product);
// this.notifyAll();
// }
System.out.println(Thread.currentThread().getName()+":"+ ++product);
// this.notifyAll();
condition.signalAll();
}finally {
lock.unlock();
}
}
//卖货
public void sale(){
lock.lock();
try {
while(product<=0){ //为了避免虚假唤醒问题,应该总是使用在循环中
System.out.println("缺货!");
try {
// this.wait();
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// else {
// System.out.println(Thread.currentThread().getName()+":"+ --product);
// this.notifyAll();
// }
System.out.println(Thread.currentThread().getName()+":"+ --product);
// this.notifyAll();
condition.signalAll();
}finally {
lock.unlock();
}
}
}
/**
* 生产者
*/
class Producer implements Runnable{
private Clerk clerk;
public Producer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
//添加延迟
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.get();
}
}
}
/**
* 消费者
*/
class Consumer implements Runnable{
private Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
//添加延迟
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.sale();
}
}
}
结果:
...
生产者C:1
产品已满!
消费者D:0
缺货!
生产者A:1
消费者B:0
生产者C:1
消费者B:0
生产者A:1
消费者D:0
生产者C:1
产品已满!
消费者B:0
缺货!
生产者A:1
消费者D:0