当多个线程同时共享,同一个全局变量或静态变量,做写的操作时,可能会发生数据冲突问题,也就是线程安全问题。但是做读操作是不会发生数据冲突问题
模拟线程安全问题
public class SafeThread implements Runnable {
private int ticketCount = 50;
@Override
public void run() {while (ticketCount > 0) {
try {Thread.sleep(50);
} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ", 出售第" + (50 - ticketCount + 1) + "张票");
ticketCount--;
}
}
}
@RequestMapping("test-safe")
public void testSafe() {SafeThread safeThread = new SafeThread();
Thread t1 = new Thread(safeThread, "thread-1");
Thread t2 = new Thread(safeThread, "thread-2");
t1.start();
t2.start();}
结果:火车票会重复出售
解决办法
使用多线程之间同步 synchronized 或使用锁(lock)
1. 同步代码块
public class SafeThread implements Runnable {
private int ticketCount = 50;
@Override
public void run() {while (ticketCount > 0) {
try {Thread.sleep(50);
} catch (InterruptedException e) {e.printStackTrace();
}
synchronized (this) {System.out.println(Thread.currentThread().getName() + ", 出售第" + (50 - ticketCount + 1) + "张票");
ticketCount--;
}
}
}
}
2. 同步方法
public class SafeThread implements Runnable {
private int ticketCount = 50;
@Override
public void run() {while (ticketCount > 0) {
try {Thread.sleep(50);
} catch (InterruptedException e) {e.printStackTrace();
}
// synchronized (this) {// System.out.println(Thread.currentThread().getName() + ", 出售第" + (50 - ticketCount + 1) + "张票");
// ticketCount--;
// }
sale();}
}
private synchronized void sale() {System.out.println(Thread.currentThread().getName() + ", 出售第" + (50 - ticketCount + 1) + "张票");
ticketCount--;
}
}
注意:同步函数使用 this 锁
3. 静态同步函数
方法上加上 static 关键字,使用 synchronized 关键字修饰或者使用类.class 文件。
静态的同步函数使用的锁是该函数所属字节码文件对象
可以用 getClass 方法获取,也可以用当前类名.class 表示
public class SafeThread implements Runnable {
private int ticketCount = 50;
@Override
public void run() {while (ticketCount > 0) {
try {Thread.sleep(50);
} catch (InterruptedException e) {e.printStackTrace();
}
// synchronized (this) {// System.out.println(Thread.currentThread().getName() + ", 出售第" + (50 - ticketCount + 1) + "张票");
// ticketCount--;
// }
// sale();
sale2();}
}
private synchronized void sale() {System.out.println(Thread.currentThread().getName() + ", 出售第" + (50 - ticketCount + 1) + "张票");
ticketCount--;
}
private void sale2() {synchronized (SafeThread.class) {System.out.println(Thread.currentThread().getName() + ", 出售第" + (50 - ticketCount + 1) + "张票");
ticketCount--;
}
}
}