线程的安全机制:锁的使用示例
1.线程和锁含义
1.2 线程中锁的作用
1.3锁的分类
1.3.1Lock锁
Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁,一般加在代码块的前后部分,不能修饰类。
1.3.1.1 Lock锁代码示例
import java.util.concurrent.locks.ReentrantLock;
/**
* 实现业务:3个业务员卖三十张票
* 使用非公平锁
*/
class Ticket1{
private int number=30;
private final ReentrantLock lock=new ReentrantLock();
public void saleticket(){
lock.lock();
try {
if(number!=0){
System.out.println(Thread.currentThread().getName()+"\t卖出的票:"+(number--)+",还剩下票数为:"+number);
}
} finally {
lock.unlock();
}
}
}
public class SafeTickeLocktDemo {
public static void main(String[] args) {
Ticket1 ticket=new Ticket1();
new Thread(()->{
for (int i = 0; i < 30; i++) {
ticket.saleticket();
}
},"窗口A").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
ticket.saleticket();
}
},"窗口B").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
ticket.saleticket();
}
},"窗口C").start();
}
}
1.3.1.2 Lock锁代码效果
1.3.2 reentrantLock锁
reentrantLock,可重入锁,ReentrantLock是唯一实现了Lock接口的类,并且ReentrantLock提供了更多的方法;构造方法(不带参数 和带参数 true: 公平锁; false: 非公平锁),同Lock一样一般修饰在执行的代码前,不能修饰类。
1.3.2.1 reentrantLock锁代码示例
import java.util.concurrent.locks.ReentrantLock;
/**
* 可重入锁
*/
class PhonePlus{
ReentrantLock reentrantLock=new ReentrantLock();
public void method1(){
reentrantLock.lock();
try {
System.out.println(Thread.currentThread().getName()+"发送邮件....");
method2();
}finally {
reentrantLock.unlock();
}
}
public void method2(){
reentrantLock.lock();
try {
System.out.println(Thread.currentThread().getName()+"发送信息....");
}finally {
reentrantLock.unlock();
}
}
}
public class ReentrantlockDemo {
public static void main(String[] args) {
PhonePlus phonePlus=new PhonePlus();
new Thread(()->{
phonePlus.method1();
},"A").start();
new Thread(()->{
phonePlus.method2();
},"B").start();
}
}
1.3.2.2 reentrantLock锁代码效果
1.3.3 synchronized锁
synchronized是java中的一个关键字,也就是说是Java语言内置的特性,采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。
1.3.3.1 synchronized锁代码示例
/**
* 实现业务:3个业务员卖三十张票
*/
class Ticket{
private int number=10;
public synchronized void saleticket(){
if(number!=0){
System.out.println(Thread.currentThread().getName()+"\t卖出的票:"+(number--)+",还剩下票数为:"+number);
}
}
}
public class SafeTicketDemo {
public static void main(String[] args) {
Ticket ticket=new Ticket();
new Thread(()->{
for (int i = 0; i < 10; i++) {
ticket.saleticket();
}
},"窗口A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
ticket.saleticket();
}
},"窗口B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
ticket.saleticket();
}
},"窗口C").start();
}
}
1.3.3.2 synchronized锁代码效果
1.3.4 AtomicReference锁
AtomicReference保证多线程环境下的原子性,相比synchronized而言更加轻量级。
1.3.4.1 AtomicReference锁代码示例
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
* 自旋锁
*/
class GC{
//AtomicReference 可以定义锁的开启和关闭
AtomicReference<Thread> atomicReference=new AtomicReference<>();
public void lock(){
Thread currentThread=Thread.currentThread();
while(!atomicReference.compareAndSet(null,currentThread)){
System.out.println(Thread.currentThread().getName()+"====等待进入中====");
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
}
System.out.println(Thread.currentThread().getName()+"====在厕所里====");
}
public void unlock(){
Thread currentThread=Thread.currentThread();
atomicReference.compareAndSet(currentThread,null);
System.out.println(currentThread.getName()+"===开门===");
}
}
public class SpinLockDemo {
public static void main(String[] args) {
GC gc =new GC();
new Thread(()->{
gc.lock();
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
gc.unlock();
}
},"A").start();
new Thread(()->{
gc.lock();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
gc.unlock();
}
},"B").start();
}
}