文章目录
前言
线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。
一、如何使线程安全?
给线程加把锁,JAVA中锁分两类,
显示锁:Lock
隐式锁:synchronized
二、隐式锁:synchronized
synchronized:Java中的关键字,是由JVM来维护的,是JVM层面的锁。
- synchronized底层是通过monitorenter进行加锁
底层是通过monitor对象来完成的,其中的wait/notify等方法也是依赖于monitor对象的。并且只有在同步块或同步方法中,JVM才会调用monitory对象的,才可以调用wait/notify等方) - 通过monitorexit来退出锁
1.使用:同步代码块:让线程变得安全
代码如下(示例):
package com.demo.thread;
public class Demo5 {
/**
* @Description: 线程同步 synchronized
* @Param: [args]
* @return: void
*/
public static void main(String[] args) {
// 线程不安全
// 解决方案1、:同步代码块
/* 格式:synchronized(锁对象){
*
* }
* */
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable).start();
new Thread(myRunnable).start();
new Thread(myRunnable).start();
}
static class MyRunnable implements Runnable {
private int count = 10;
private Object o = new Object(); //三条线程,一个对象。
@Override
public void run() {
while (true) {
synchronized (o) { //线程同步
if (count > 0) {
System.out.println("正在准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName() + "出票成功:余票:" + count);
} else {
break;
}
}
}
}
}
}
2.使用:同步方法:让线程安全
代码如下(示例):
package com.demo.thread;
public class Demo6 {
/**
* @Description: 线程同步 synchronized
* @Param: [args]
* @return: void
*/
public static void main(String[] args) {
// 线程不安全
// 解决方案2、:同步方法
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable).start();
new Thread(myRunnable).start();
new Thread(myRunnable).start();
}
static class MyRunnable implements Runnable {
private int count = 10;
private Object o = new Object();
@Override
public void run() {
while (true) {
boolean flag = sale();
if (!flag) {
break;
}
}
}
public synchronized boolean sale() {
// 锁对象:在方法的内部操作的this是谁,那么这个锁就是谁。
// 如果方法被静态修饰,那么锁就是 类名.class
if (count > 0) {
System.out.println("正在准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName() + "出票成功:余票:" + count);
return true;
}
return false;
}
}
}
三、显示锁:Lock
Lock:是JDK5以后才出现的具体的类。使用lock是调用对应的API,是API层面的锁。
- lock是通过调用对应的API方法来获取锁和释放锁的。
1.使用 Lock
// 显示锁 l
private Lock l = new ReentrantLock();
package com.demo.thread;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Demo7 {
/**
* 同步代码块 和 同步方法,称为 隐式锁
*
* @Description: 线程同步 Lock
* @Param: [args]
* @return: void
*/
public static void main(String[] args) {
// 线程不安全
// 解决方案3、:显示锁 Lock 子类:ReentrantLock
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable).start();
new Thread(myRunnable).start();
new Thread(myRunnable).start();
}
static class MyRunnable implements Runnable {
private int count = 10;
private Object o = new Object();
// 显示锁 l
private Lock l = new ReentrantLock();
@Override
public void run() {
while (true) {
l.lock(); //上锁
if (count > 0) {
System.out.println("正在准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName() + "出票成功:余票:" + count);
} else {
break;
}
l.unlock(); // 解锁
}
}
}
}