Lock多线程模式下的使用记住三个步骤
a.判断 while条件判断 多线程模式下一定是while
b.干活 执行业务代码
c.通知 唤醒下一个要运行的线程
还得记住 线程操作资源类,资源类要定义好 condition条件别忘了
1.一个初始值为0的变量 两个线程对其交替操作一个加1 一个减1 来5轮(生产者 消费者模拟)
/**
* 一个初始值为0的变量 两个线程对其交替操作
* 一个加1 一个减1 来5轮
*/
public class ProdConsumer {
public static void main(String[] args) {
ShareDate shareDate = new ShareDate();
new Thread(()->{
try {
for (int i = 1; i < 5; i++) {
shareDate.increment();
}
} catch (Exception e) {
e.printStackTrace();
}
},"aa").start();
new Thread(()->{
try {
for (int i = 1; i < 5; i++) {
shareDate.decrement();
}
} catch (Exception e) {
e.printStackTrace();
}
},"bb").start();
}
}
class ShareDate{
private int number = 0 ;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void increment(){
//判断
lock.lock();
try {
while(number != 0){
//等待 不能生产
condition.await();
}
//干活
number++;
System.out.println(Thread.currentThread().getName()+"--"+number);
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void decrement() throws Exception{
//判断
lock.lock();
try {
while(number == 0){
//等待 不能生产
condition.await();
}
//干活
number--;
System.out.println(Thread.currentThread().getName()+"--"+number);
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
2.生产者消费者加强版,BlockQueue
使用阻塞队列好处:我们不需要关系什么时候阻塞线程,什么时候唤醒线程
class MyResource{
private volatile boolean flag = true;
private AtomicInteger atomicInteger = new AtomicInteger();
BlockingQueue<String> blockingQueue = null;
public MyResource(BlockingQueue<String> blockingQueue) {
this.blockingQueue = blockingQueue;
System.out.println(blockingQueue.getClass().getName());
}
public void myProd() throws InterruptedException {
String data = null;
boolean retvalue;
while(flag) {
data = atomicInteger.incrementAndGet()+"";
retvalue = blockingQueue.offer(data,2L, TimeUnit.SECONDS);
if (retvalue) {
System.out.println(Thread.currentThread().getName()+"插入队列:"+data+"成功");
}else {
System.out.println(Thread.currentThread().getName()+"插入队列:"+data+"失败");
}
TimeUnit.SECONDS.sleep(1);
}
System.out.println(Thread.currentThread().getName()+"生产结束");
}
public void myCons() throws InterruptedException {
String result = null;
//TimeUnit.SECONDS.sleep(10);
while (flag){
result = blockingQueue.poll(2L,TimeUnit.SECONDS);
if(null == result || result.equalsIgnoreCase("")){
flag = false;
System.out.println(Thread.currentThread().getName()+"消费超时,退出");
return;
}
System.out.println(Thread.currentThread().getName()+"消费队列"+result+"成功");
}
}
public void stop() throws Exception{
this.flag = false;
}
}
public class ProdConsumer_BlockQueue {
public static void main(String[] args) throws Exception{
MyResource myResource = new MyResource(new ArrayBlockingQueue<>(3));
new Thread(() ->{
System.out.println(Thread.currentThread().getName()+"启动");
try {
myResource.myProd();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"prod").start();
new Thread(() ->{
System.out.println(Thread.currentThread().getName()+"启动");
try {
myResource.myCons();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"cons").start();
TimeUnit.SECONDS.sleep(5);
System.out.println();
System.out.println("5秒后main叫停");
myResource.stop();
}
}
结果:
java.util.concurrent.ArrayBlockingQueue
prod启动
prod插入队列:1成功
cons启动
cons消费队列1成功
prod插入队列:2成功
cons消费队列2成功
prod插入队列:3成功
cons消费队列3成功
prod插入队列:4成功
cons消费队列4成功
prod插入队列:5成功
cons消费队列5成功
5秒后main叫停
prod生产结束
cons消费超时,退出
思考下 消费者先不消费的场景 如下代码所示
class MyResource{
private volatile boolean flag = true;
private AtomicInteger atomicInteger = new AtomicInteger();
BlockingQueue<String> blockingQueue = null;
public MyResource(BlockingQueue<String> blockingQueue) {
this.blockingQueue = blockingQueue;
System.out.println(blockingQueue.getClass().getName());
}
public void myProd() throws InterruptedException {
String data = null;
boolean retvalue;
while(flag) {
data = atomicInteger.incrementAndGet()+"";
retvalue = blockingQueue.offer(data,2L, TimeUnit.SECONDS);
if (retvalue) {
System.out.println(Thread.currentThread().getName()+"插入队列:"+data+"成功");
}else {
System.out.println(Thread.currentThread().getName()+"插入队列:"+data+"失败");
}
TimeUnit.SECONDS.sleep(1);
}
System.out.println(Thread.currentThread().getName()+"生产结束");
}
public void myCons() throws InterruptedException {
String result = null;
TimeUnit.SECONDS.sleep(10);
while (flag){
result = blockingQueue.poll(2L,TimeUnit.SECONDS);
if(null == result || result.equalsIgnoreCase("")){
flag = false;
System.out.println(Thread.currentThread().getName()+"消费超时,退出");
return;
}
System.out.println(Thread.currentThread().getName()+"消费队列"+result+"成功");
}
}
public void stop() throws Exception{
this.flag = false;
}
}
public class ProdConsumer_BlockQueue {
public static void main(String[] args) throws Exception{
MyResource myResource = new MyResource(new ArrayBlockingQueue<>(3));
new Thread(() ->{
System.out.println(Thread.currentThread().getName()+"启动");
try {
myResource.myProd();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"prod").start();
new Thread(() ->{
System.out.println(Thread.currentThread().getName()+"启动");
try {
myResource.myCons();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"cons").start();
TimeUnit.SECONDS.sleep(20);
System.out.println();
System.out.println("20秒后main叫停");
myResource.stop();
}
}
结果
java.util.concurrent.ArrayBlockingQueue
prod启动
prod插入队列:1成功
cons启动
prod插入队列:2成功
prod插入队列:3成功
prod插入队列:4失败
prod插入队列:5失败
cons消费队列1成功
cons消费队列2成功
cons消费队列3成功
cons消费队列6成功
prod插入队列:6成功
prod插入队列:7成功
cons消费队列7成功
prod插入队列:8成功
cons消费队列8成功
prod插入队列:9成功
cons消费队列9成功
prod插入队列:10成功
cons消费队列10成功
prod插入队列:11成功
cons消费队列11成功
prod插入队列:12成功
cons消费队列12成功
prod插入队列:13成功
cons消费队列13成功
prod插入队列:14成功
cons消费队列14成功
prod插入队列:15成功
cons消费队列15成功
20秒后main叫停
prod生产结束
cons消费超时,退出
3.实现AA--BB--CC三个线程启动 要求
AA打印5次后BB打印10次 cc打印15次 紧接着 AA打印5次后BB打印10次 cc打印15次
来十轮
package com.example.starter;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//线程操作资源类
class ShareResoucre{
private int number = 1;
private Lock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();
public void prints5(){
lock.lock();
try {
//判断
while(number != 1){
c1.await();
}
//干活
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"--"+i);
}
// //通知
number = 2;
c2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void prints10(){
lock.lock();
try {
//判断
while(number != 2){
c2.await();
}
//干活
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"--"+i);
}
// //通知
number = 3;
c3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void prints15(){
lock.lock();
try {
//判断
while(number != 3){
c3.await();
}
//干活
for (int i = 0; i < 15; i++) {
System.out.println(Thread.currentThread().getName()+"--"+i);
}
// //通知
number = 1;
c1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class SynAndReentrantLockDemo {
public static void main(String[] args) {
ShareResoucre shareResoucre = new ShareResoucre();
for (int i = 0; i < 10; i++) {
new Thread(() ->{
shareResoucre.prints5();
},"AA").start();
new Thread(() ->{
shareResoucre.prints10();
},"BB").start();
new Thread(() ->{
shareResoucre.prints15();
},"CC").start();
}
}
}
4.尝试使用如下方式实现步骤3的需求
此方式会造成死循环,因为使用同一个lock锁对象,进入某个方法时 number不满足条件将会无限循环 不释放锁
//线程操作资源类
class ShareResoucre{
private volatile int number = 1;
private Lock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();
public void prints5(){
lock.lock();
try {
//System.out.println("prints5");
//判断
while(number != 1){
Thread.sleep(3);
// c1.await();
}
//干活
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"--"+i);
}
// //通知
number = 2;
//c2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void prints10(){
lock.lock();
try {
//判断
while(number != 2){
// c2.await();
}
//干活
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"--"+i);
}
// //通知
number = 3;
//c3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void prints15(){
lock.lock();
try {
//判断
while(number != 3){
//c3.await();
}
//干活
for (int i = 0; i < 15; i++) {
System.out.println(Thread.currentThread().getName()+"--"+i);
}
// //通知
number = 1;
//c1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class SynAndReentrantLockDemo {
public static void main(String[] args) {
ShareResoucre shareResoucre = new ShareResoucre();
for (int i = 0; i < 10; i++) {
new Thread(() ->{
shareResoucre.prints5();
},"AA").start();
new Thread(() ->{
shareResoucre.prints10();
},"BB").start();
new Thread(() ->{
shareResoucre.prints15();
},"CC").start();
}
}
}
5.可以使用如下方式优化,创建三个锁对象
//线程操作资源类
class ShareResoucre{
private volatile int number = 1;
private Lock lock1 = new ReentrantLock();
private Lock lock2 = new ReentrantLock();
private Lock lock3 = new ReentrantLock();
/* private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();*/
public void prints5(){
lock1.lock();
try {
//判断
while(number != 1){
Thread.sleep(3);
// c1.await();
}
//干活
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"--"+i);
}
// //通知
number = 2;
//c2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock1.unlock();
}
}
public void prints10(){
lock2.lock();
try {
//判断
while(number != 2){
// c2.await();
}
//干活
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"--"+i);
}
// //通知
number = 3;
//c3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock2.unlock();
}
}
public void prints15(){
lock3.lock();
try {
//判断
while(number != 3){
//c3.await();
}
//干活
for (int i = 0; i < 15; i++) {
System.out.println(Thread.currentThread().getName()+"--"+i);
}
// //通知
number = 1;
//c1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock3.unlock();
}
}
}
public class SynAndReentrantLockDemo {
public static void main(String[] args) {
ShareResoucre shareResoucre = new ShareResoucre();
for (int i = 0; i < 10; i++) {
new Thread(() ->{
shareResoucre.prints5();
},"AA").start();
new Thread(() ->{
shareResoucre.prints10();
},"BB").start();
new Thread(() ->{
shareResoucre.prints15();
},"CC").start();
}
}
}