1 演示线程安全问题的小案例
public class ThreadSecurityDemo implements Runnable{
private int ticket = 100;
//模拟多线程票务系统,有3条线程同时修改共享的ticket,引发线程安全问题
@Override
public void run() {
while (ticket > 0){
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName() + "正在出售第" + (101 - ticket) +"张票");
ticket--;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class TestThreadSecurityDemo {
public static void main(String[] args) {
ThreadSecurityDemo run = new ThreadSecurityDemo();
Thread thread1 = new Thread(run);
Thread thread2 = new Thread(run);
Thread thread3 = new Thread(run);
thread1.start();
thread2.start();
thread3.start();
}
}
2 线程同步
线程安全问题都是由全局变量和静态变量引起的,若每个线程中对全局变量静态变量只有读操作,而无写操作,一般来说这个全局变量是线程安全的,若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话影响线程安全。
同步的方式有三种:
- 同步代码块
- 同步方法
- 锁机制
2.1 使用同步代码块解决线程安全问题
public class ThreadSynchronized implements Runnable{
//解决线程安全问题的一种方案:同步代码块,只让一个线程在同步代码块中执行
//格式:synchronized(锁对象){}
private int ticket = 100;
//模拟多线程票务系统,有3条线程同时修改共享的ticket,引发线程安全问题
//创建一个锁对象
Object obj = new Object();
@Override
public void run() {
while (true){
synchronized (obj){
if(ticket > 0){
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName() + "正在出售第" + (101 - ticket) +"张票");
ticket--;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
同步代码块保证了只能有一个线程在同步中执行共享数据,保证了安全,程序的频繁的判断锁,获取锁,释放锁,程序的效率会降低
2.2使用同步方法解决线程安全问题
public class ThreadSynchronizedMethod implements Runnable{
//解决线程安全问题的第二种方案:同步方法
private int ticket = 100;
//模拟多线程票务系统,有3条线程同时修改共享的ticket,引发线程安全问题
@Override
public void run() {
while (true){
sellTicket();
}
}
public synchronized void sellTicket(){
if(ticket > 0){
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName() + "正在出售第" + (101 - ticket) +"张票");
ticket--;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
同步方法也会把方法内部的代码锁住,只让一个线程执行。同步方法的锁对象是实现类对象
2.3 使用lock锁解决线程安全问题
解决线程安全问题的第三种解决方案:使用Lock锁
Lock锁实现提供了比使用synchronized方法更广泛的锁定操作,
Lock接口中的方法:
- void lock()获取锁
- void unlock()释放锁
public class ThreadLock implements Runnable{
private int ticket = 100;
Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock();
if(ticket > 0){
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName() + "正在出售第" + (101 - ticket) +"张票");
ticket--;
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}
}