面试重点 java并发编程
lock接口
ReentrantLock最常用
假如有一个执行时间为2h、2s顺序排列的线程,可以插队的话,就不至于让2s的线程等太久
package com.MulThread;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockPractice {
public static void main(String[] args) {
Ticket1 t = new Ticket1();
new Thread(()->{
for (int i = 0; i < 30; i++) {
t.saleTicket();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
t.saleTicket();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
t.saleTicket();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
}
}
//如果implements runnable 接口的话 耦合性会强
//使用函数式接口(一个接口仅有一个抽象函数)
class Ticket1{
private int num=50;
public void saleTicket(){
Lock l = new ReentrantLock();//
l.lock();//加锁
try {
//业务代码
if (num>0)
System.out.println(Thread.currentThread().getName()+"卖出了第"+(num--)+"张票,还剩"+num+"张票!");
}catch (Exception e){
e.printStackTrace();
}
finally {
l.unlock();
}
}
}
以上相当于手动挡,自动挡如下
package com.MulThread;
public class ThreadPractice {
public static void main(String[] args) {
Ticket t = new Ticket();
new Thread(
()-> {
for (int i = 0; i < 30; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.saleTicket();
}
},"A"
).start();
new Thread(
new Runnable() {
@Override
public void run() {
for (int i = 0; i < 30; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.saleTicket();
}
}
},"B"
).start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.saleTicket();
}
},"C").start();
}
}
//如果implements runnable 接口的话 耦合性会强
//使用函数式接口(一个接口仅有一个抽象函数)
class Ticket{
private static int num=50;
public synchronized void saleTicket(){
if (num>0)
System.out.println(Thread.currentThread().getName()+"卖出了第"+num--+"张票,还剩"+num+"张票!");
}
}
synchronized和lock的区别
1.synchronized是java关键字,lock是java一个类(接口);
2.synchronized是可重入锁,不可以中断,非公平锁;lock是可重入锁,可以判断锁,非公平锁(可变);
3.(自动挡和手动挡的区别)synchronized会自动释放锁,而lock需要手动释放,否则会产生死锁;
4.synchronized无法判断获取锁的状态,lock可判断是否获取到了锁;
5.synchronized适合锁少量的代码同步问题;而lock适合锁大量的代码同步问题
6.在使用synchronized锁时,线程1获得锁,线程3就会傻等,而lock锁不一定会等待下去
生产者和消费者问题
synchronized版本
package com.ShengChanXiaoFei;
public class ConsumerPra {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
// 判断等待 业务 通知 (口诀)
class Data{
private int num=0;
// 生产操作
public synchronized void increment() throws InterruptedException {
while(num!=0){
// 等待
System.out.println(Thread.currentThread().getName()+"在等");
this.wait();
}
num++;
// 业务
System.out.println(Thread.currentThread().getName()+"===>"+num);
this.notifyAll();
// 通知其它小伙伴来运行
}
// 消费操作
public synchronized void decrement() throws InterruptedException {
while(num==0){
// 因为没有产品可以消费了 等待
System.out.println(Thread.currentThread().getName()+"在等");
this.wait();
}
// 业务
num--;
System.out.println(Thread.currentThread().getName()+"==>"+num);
// 通知
this.notifyAll();
}
}
判断的地方如何把while改为if的话 问题A、B两个线程是安全的。但A、B、C、D四个线程时不安全
if只判断1次会存在虚假唤醒的问题
JUC版本的生产者和消费问题
package com.ShengChanXiaoFei;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockPra {
public static void main(String[] args) {
Data1 d = new Data1();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
d.increment();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
d.decrement();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
d.increment();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
d.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
// 判断等待 业务 通知 (口诀)
class Data1{
private static int num=0;
Lock lock = new ReentrantLock();
Condition conditionA = lock.newCondition();
// 生产操作
public void increment() throws InterruptedException {
lock.lock();
try{
// 业务代码
while(num!=0){
// 等待
// System.out.println(Thread.currentThread().getName()+"在等");
// this.wait();
conditionA.await();
}
num++;
// 业务
System.out.println(Thread.currentThread().getName()+"===>"+num);
// this.notifyAll();
// 通知其它小伙伴来运行
conditionA.signalAll();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
// 消费操作
public void decrement() throws InterruptedException {
lock.lock();
try {
while(num==0){
// 因为没有产品可以消费了 等待
// System.out.println(Thread.currentThread().getName()+"在等");
// this.wait();
conditionA.await();
}
// 业务
num--;
System.out.println(Thread.currentThread().getName()+"==>"+num);
// 通知
// this.notifyAll();
conditionA.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
使用lock精准控制 A执行了通知B、 B执行了通知C、C执行了通知A
package com.ShengChanXiaoFei;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockLiuShui {
public static void main(String[] args) {
Data3 d = new Data3();
new Thread(()->{
for (int i = 0; i < 20; i++) {
try {
d.printC();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(()->{
for (int i = 0; i < 20; i++) {
try {
d.printA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(()->{
for (int i = 0; i < 20; i++) {
try {
d.printB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
// A执行完唤醒B B执行完唤醒C C执行完唤醒A
class Data3{
private int number = 1;
//资源类 lock
private Lock lock = new ReentrantLock();
private Condition conditionA = lock.newCondition();
private Condition conditionB = lock.newCondition();
private Condition conditionC= lock.newCondition();
public void printA() throws InterruptedException {
lock.lock();
try {
while (number!=1){
// 等待
conditionA.await();
}
number=2;
System.out.println(Thread.currentThread().getName()+"==>"+number+"AAAAAAA");
// 业务
conditionB.signal();
// 通知
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void printB() throws InterruptedException {
lock.lock();
try {
while(number!=2){
// 等待
conditionB.await();
}
// 业务
number=3;
System.out.println(Thread.currentThread().getName()+"==>"+number+"B");
conditionC.signal();
// 通知c
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void printC() throws InterruptedException {
lock.lock();
try {
while (number!=3){
// 等待
conditionC.await();
}
// 业务
number=1;
System.out.println(Thread.currentThread().getName()+"==>"+number+"C");
// 通知
conditionA.signal();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}