当我们使用多线程访问同一个资源时,且多个线程对资源有写的 操作就容易出现线程安全问题,java为了解决线程安全问题引入了同步机制来解决,即在一个线程使用公共代码块的时候另一个线程不可以使用
下面我用一个抢票的案例来给大家讲解保证线程安全的几种方式
首先我们先来看看没有使用锁的情况下出现的情况
package ThreadSafe;
public class ThreadSafe implements Runnable {
//定义一个多线程共享的 票源
private int ticketsum=100;
//设置买票的线程任务
public void run(){
while(true) {
//判断还有没有票
if (ticketsum > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖:" + ticketsum);
ticketsum--;
}
}
}
}
package ThreadSafe;
public class Main {
public static void main(String[] args) {
//创建Runable实现对象
ThreadSafe threadSafe = new ThreadSafe();
//创建Thread类对象
Thread one = new Thread(threadSafe, "一号");
Thread two = new Thread(threadSafe, "二号");
Thread three = new Thread(threadSafe, "三号");
one.start();
two.start();
three.start();
}
}
对于线程安全原理不懂的兄弟可以去看看我的另一篇文章
链接:https://blog.csdn.net/pjh88/article/details/107359745
下面演示加锁的情况
同步代码块:synchronized关键字可以用于某个区块中,表示对这个区块的资源实行互斥访问
synchronized(同步锁){
需要同步操作的代码
}
同步锁:
对象的同步锁只是一个概念,可以想象为在改对象上上了一把锁
1.锁可以是任意的类型
2.多个线程对象要使用同一把锁
任何时候都最多允许一个对象拥有同步锁谁拿到锁就谁进入同步代码块
使用以下代码块来演示
package ThreadSafe;
public class Main {
public static void main(String[] args) {
//创建Runable实现对象
ThreadSafe threadSafe = new ThreadSafe();
//创建Thread类对象
Thread one = new Thread(threadSafe, "一号");
Thread two = new Thread(threadSafe, "二号");
Thread three = new Thread(threadSafe, "三号");
one.start();
two.start();
three.start();
}
}
package ThreadSafe;
public class ThreadSafe implements Runnable {
//定义一个多线程共享的 票源
private int ticketsum=100;
java.lang.Object object=new java.lang.Object();
//设置买票的线程任务
public void run(){
while(true) {
synchronized (object){
//判断还有没有票
if (ticketsum > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖:" + ticketsum);
ticketsum--;
}
}
}
}
}
什么是同步方法?
使用synchronized修饰的方法叫做同步方法,保证线程安全,当a线程执行该方法的时候,其他线程只可以在方法外等待
public synchornized void method(){
可能产生线程安全的代码块
}
那么锁对象在哪呢?
锁对象是隐藏的,谁调用这个方法谁就是隐藏的锁对象,
对于非static方法锁对象就是this
对于static方法锁对象是类名.class
上代码
package ThreadSafe;
public class ThreadSafe implements Runnable {
//定义一个多线程共享的 票源
private int ticketsum=100;
java.lang.Object object=new java.lang.Object();
//设置买票的线程任务
public void run(){
while(true) {
shuchu();
}
}
public synchronized void shuchu(){
//判断还有没有票
if (ticketsum > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖:" + ticketsum);
ticketsum--;
}
}
}
package ThreadSafe;
public class Main {
public static void main(String[] args) {
//创建Runable实现对象
ThreadSafe threadSafe = new ThreadSafe();
//创建Thread类对象
Thread one = new Thread(threadSafe, "一号");
Thread two = new Thread(threadSafe, "二号");
Thread three = new Thread(threadSafe, "三号");
one.start();
two.start();
three.start();
}
}
结果
由结果可以看出没有出现线程安全的问题
另一种实现方法
上代码
package ThreadSafe;
public class ThreadSafe implements Runnable {
//定义一个多线程共享的 票源
private int ticketsum=100;
java.lang.Object object=new java.lang.Object();
//设置买票的线程任务
public void run(){
while(true) {
shuchu();
}
}
public void shuchu(){
synchronized(this) {
//判断还有没有票
if (ticketsum > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖:" + ticketsum);
ticketsum--;
}
}
}
}
package ThreadSafe;
public class Main {
public static void main(String[] args) {
//创建Runable实现对象
ThreadSafe threadSafe = new ThreadSafe();
//创建Thread类对象
Thread one = new Thread(threadSafe, "一号");
Thread two = new Thread(threadSafe, "二号");
Thread three = new Thread(threadSafe, "三号");
one.start();
two.start();
three.start();
}
}
所得的结果和上面是一样的
java.util.concurrent.locks.Lock 机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作, 同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象。
Lock锁的功能
public void lock()加同步锁
public void unlock() 释放同步锁
下面使用一段代码演示
package ThreadSafe;
public class Main {
public static void main(String[] args) {
//创建Runable实现对象
ThreadSafe threadSafe = new ThreadSafe();
//创建Thread类对象
Thread one = new Thread(threadSafe, "一号");
Thread two = new Thread(threadSafe, "二号");
Thread three = new Thread(threadSafe, "三号");
one.start();
two.start();
three.start();
}
}
package ThreadSafe;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadSafe implements Runnable {
//定义一个多线程共享的 票源
private int ticketsum=100;
ReentrantLock lock=new ReentrantLock();
//设置买票的线程任务
public void run(){
while(true) {
shuchu();
}
}
public void shuchu(){
while (true){
lock.lock();
//判断还有没有票
if (ticketsum > 0) {
try {
Thread.sleep(10);
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖:" + ticketsum);
ticketsum--;
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}
}