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代碼塊裏解鎖.
查看更多例子和源碼請戳這裏