java基础 解决多线程安全问题的方法
- synchronized 代码块
- synchronized 方法
- Lock 锁
下面以一个卖票的程序对知识点进行演示。
- synchronized 代码块
格式 synchronized (){ }
方法实现如下:
public class SynchronizedDemo {
public static void main(String[] args){
//new一个Runnable接口的实现类
RunnableImpl runnable = new RunnableImpl();
//new三个新线程
Thread thread = new Thread(runnable);
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
//设置各个线程的名字
thread.setName("马云");
thread1.setName("王健林");
thread2.setName("王建国");
//开启线程
thread.start();
thread1.start();
thread2.start();
}
}
public class RunnableImpl implements Runnable {
private int ticket = 10;
private int count = 0;
//new 一个对象(随意的对象),作为synchronized代码块的接收锁,关于这个知识点有问题的可以先看知识点3---Lock锁的讲解作为理解
Object obj = new Object();
@Override
public void run() {
while (true) {
if (ticket < 1)break;
//接收Object类作为接收锁,三个线程抢夺一个接收锁,当其中一个线程争夺到使用权,其他线程进行等待
synchronized (obj){
if (ticket > 0) {
ticket--;
count++;
System.out.println(Thread.currentThread().getName() + "正在卖第" + count + "张票。");
try {
//使当前线程沉睡100毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
运行结果:
马云正在卖第1张票。
王健林正在卖第2张票。
王建国正在卖第3张票。
王建国正在卖第4张票。
王建国正在卖第5张票。
王建国正在卖第6张票。
王健林正在卖第7张票。
马云正在卖第8张票。
王健林正在卖第9张票。
王健林正在卖第10张票。
再次运行:
马云正在卖第1张票。
马云正在卖第2张票。
马云正在卖第3张票。
王建国正在卖第4张票。
王建国正在卖第5张票。
王健林正在卖第6张票。
王健林正在卖第7张票。
王健林正在卖第8张票。
王健林正在卖第9张票。
王健林正在卖第10张票。
Process finished with exit code 0
2. synchronized 方法
格式:修饰符 synchronized 返回值类型 方法名 (参数列表){ }
方法实现如下:
public class SynchronizedDemo {
public static void main(String[] args){
RunnableImpl runnable = new RunnableImpl();
//开启三个新线程
Thread thread = new Thread(runnable);
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
thread.setName("马云");
thread1.setName("王健林");
thread2.setName("王建国");
thread.start();
thread1.start();
thread2.start();
}
}
public class RunnableImpl implements Runnable {
private int ticket = 10;
private int count = 0;
@Override
public void run() {
while (true) {
if (ticket < 1)break;
synchronizedMethod();
}
}
//用synchronized关键字创建方法
public synchronized void synchronizedMethod(){
if (ticket > 0) {
ticket--;
count++;
System.out.println(Thread.currentThread().getName() + "正在卖第" + count + "张票。");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果:
马云正在卖第1张票。
马云正在卖第2张票。
马云正在卖第3张票。
马云正在卖第4张票。
马云正在卖第5张票。
王建国正在卖第6张票。
王健林正在卖第7张票。
王健林正在卖第8张票。
王建国正在卖第9张票。
王建国正在卖第10张票。
Process finished with exit code 0
再次运行:
马云正在卖第1张票。
马云正在卖第2张票。
马云正在卖第3张票。
马云正在卖第4张票。
马云正在卖第5张票。
王建国正在卖第6张票。
王建国正在卖第7张票。
王建国正在卖第8张票。
王建国正在卖第9张票。
王建国正在卖第10张票。
Process finished with exit code 0
3. Lock 锁
java.util.concurrent.locks包下的Lock接口。
public void lock():加同步锁。
public void unlock():释放同步锁。
方法实现如下:
public class LockDemo {
public static void main(String[] args){
RunnableImpl runnable = new RunnableImpl();
//开启三个新线程
Thread thread = new Thread(runnable);
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
thread.setName("马云");
thread1.setName("王健林");
thread2.setName("王建国");
thread.start();
thread1.start();
thread2.start();
}
}
public class RunnableImpl implements Runnable {
private int ticket = 10;
private int count = 0;
//new一个Lock接口的实现类ReentrantLock(),利用多态对Lock接口中的方法 进行使用
Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
if (ticket < 1)break;
//加同步锁,三个线程随机一个进行一下代码,其他两个线程进行等待
lock.lock();
if (ticket > 0) {
ticket--;
count++;
System.out.println(Thread.currentThread().getName() + "正在卖第" + count + "张票。");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//释放同步锁
lock.unlock();
}
}
运行结果:
马云正在卖第1张票。
马云正在卖第2张票。
马云正在卖第3张票。
马云正在卖第4张票。
马云正在卖第5张票。
王健林正在卖第6张票。
王健林正在卖第7张票。
王健林正在卖第8张票。
王健林正在卖第9张票。
王健林正在卖第10张票。
Process finished with exit code 0
再次运行:
马云正在卖第1张票。
王健林正在卖第2张票。
王健林正在卖第3张票。
王建国正在卖第4张票。
王建国正在卖第5张票。
王建国正在卖第6张票。
王建国正在卖第7张票。
王建国正在卖第8张票。
王建国正在卖第9张票。
王建国正在卖第10张票。
Process finished with exit code 0