1 多线程容易出现问题
举个例子,电影院卖票,一共卖100张票,分3个窗口,用多线程来模拟,看会发生什么?
1-1 创建一个卖票任务,实现Runnable接口
public class Ticket implements Runnable{
// 总共100
private int ticket = 100;
@Override
public void run() {
while (true){
if (ticket>0){
try {
// 处理卖票耗时
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println(name+"正在卖票"+ticket--);
}
}
}
}
1-2 创建3个线程,来卖票
public class Test {
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread t1 = new Thread(ticket, "线程1");
Thread t2 = new Thread(ticket, "线程2");
Thread t3 = new Thread(ticket, "线程3");
t1.start();
t2.start();
t3.start();
}
}
1-3 出现的问题
- 相同的票被卖了2次,如下图
- 不存在的票,如0或者1
若有多个线程同时执行写的操作,那么需要考虑线程同步,否则的话,可能影响线程安全。
2 同步代码块 synchronized
synachronized(同步锁){
需要同步操作的代码
}
2-1 使用同步锁的方式来创建Runnable的实现类
public class Ticket implements Runnable{
// 总共100
private int ticket = 100;
Object obj = new Object();
@Override
public void run() {
while (true){
synchronized (obj){
if (ticket>0){
try {
// 处理卖票耗时
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println(name+"正在卖票"+ticket--);
}
}
}
}
}
3 使用同步方法来解决线程安全
使用synchronized修饰的方法,就是同步方法,可以保证一个线程执行该方法的同时,其它的线程只能在方法的外边等候
public class Ticket implements Runnable{
// 总共100
private int ticket = 100;
@Override
public void run() {
while (true){
sellTicket();
}
}
public synchronized void sellTicket(){
if (ticket>0){
try {
// 处理卖票耗时
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println(name+"正在卖票"+ticket--);
}
}
}
4 使用lock锁
synachronized(同步锁){
需要同步操作的代码
}
2-1 使用同步锁的方式来创建Runnable的实现类
public class Ticket implements Runnable{
// 总共100
private int ticket = 100;
Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock();
if (ticket>0){
try {
// 处理卖票耗时
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println(name+"正在卖票"+ticket--);
}
lock.unlock();
}
}
}