java并发线程带来的安全问题
场景模拟
创建三个线程模拟三个售票窗口,来同时出售一百张票
代码
package com.shemuel;
/**
* @Author: dengshaoxiang
* @Date: 2019/6/11 15:46
* @Description:
*/
public class ThreadDemo {
public static void main(String[] args) {
MyTicket ticket = new MyTicket();
new Thread(ticket,"一号窗口").start();
new Thread(ticket,"二号窗口").start();
new Thread(ticket,"三号窗口").start();
}
}
class MyTicket implements Runnable{
// 一百张票
private int ticket = 100;
@Override
public void run() {
while (true) {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "售票完成,余票 : " + --ticket);
}
}
}
}
运行程序,结果:
可以看到结果数据产生了问题.
解决方法
方法一 :同步代码块
代码:
package com.shemuel;
/**
* @Author: dengshaoxiang
* @Date: 2019/6/11 15:46
* @Description:
*/
public class ThreadDemo {
public static void main(String[] args) {
MyTicket ticket = new MyTicket();
new Thread(ticket,"一号窗口").start();
new Thread(ticket,"二号窗口").start();
new Thread(ticket,"三号窗口").start();
}
}
class MyTicket implements Runnable{
// 一百张票
private int ticket = 100;
@Override
public void run() {
sellTicket();
}
public synchronized void sellTicket() {
while (true) {
if (ticket > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "售票完成,余票 : " + --ticket);
}
}
}
}
结果:
方法二 : 同步方法
代码:
package com.shemuel;
/**
* @Author: dengshaoxiang
* @Date: 2019/6/11 15:46
* @Description:
*/
public class ThreadDemo {
public static void main(String[] args) {
MyTicket ticket = new MyTicket();
new Thread(ticket,"一号窗口").start();
new Thread(ticket,"二号窗口").start();
new Thread(ticket,"三号窗口").start();
}
}
class MyTicket implements Runnable{
// 一百张票
private int ticket = 100;
@Override
public void run() {
synchronized (this){
while (true) {
if (ticket > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "售票完成,余票 : " + --ticket);
}
}
}
}
}
结果:
方法三 : Lock同步锁
代码:
package com.shemuel;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Author: dengshaoxiang
* @Date: 2019/6/11 15:46
* @Description:
*/
public class ThreadDemo {
public static void main(String[] args) {
MyTicket ticket = new MyTicket();
new Thread(ticket,"一号窗口").start();
new Thread(ticket,"二号窗口").start();
new Thread(ticket,"三号窗口").start();
}
}
class MyTicket implements Runnable{
private Lock lock = new ReentrantLock();
// 一百张票
private int ticket = 100;
@Override
public void run() {
while (true) {
lock.lock();
try {
if (ticket > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "售票完成,余票 : " + --ticket);
}
}finally {
lock.unlock();
}
}
}
}
结果:
注意:lock 一定要在finally代码块里解锁.
查看更多例子和源码请戳这里