线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
举个例子,正常情况下,一张火车票只能卖给一个人,但是在售票的核心代码块的地方你并没有加锁,就可能会出现线程不安全的情况,从而导致一张火车票可能会卖给多个人的情况发生。
static class SellTickets implements Runnable {
@Override
public void run() {
while (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "--->售出第: " + tickets + " 票");
tickets--;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (tickets <= 0) {
System.out.println(Thread.currentThread().getName() + "--->售票结束!");
}
}
}
public static void main(String[] args) {
SellTickets sell = new SellTickets();
Thread thread1 = new Thread(sell, "1号窗口");
Thread thread2 = new Thread(sell, "2号窗口");
Thread thread3 = new Thread(sell, "3号窗口");
Thread thread4 = new Thread(sell, "4号窗口");
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
1号窗口--->售出第: 10 票
4号窗口--->售出第: 10 票
3号窗口--->售出第: 10 票
2号窗口--->售出第: 10 票
3号窗口--->售出第: 6 票
2号窗口--->售出第: 6 票
4号窗口--->售出第: 6 票
1号窗口--->售出第: 6 票
3号窗口--->售出第: 2 票
4号窗口--->售出第: 2 票
2号窗口--->售出第: 2 票
1号窗口--->售出第: 2 票
3号窗口--->售票结束!
1号窗口--->售票结束!
4号窗口--->售票结束!
2号窗口--->售票结束!
Process finished with exit code 0
static class SellTickets implements Runnable {
Lock lock = new ReentrantLock();
@Override
public void run() {
// Lock锁机制
while (tickets > 0) {
try {
lock.lock();
if (tickets <= 0) {
return;
}
System.out.println(Thread.currentThread().getName() + "--->售出第: " + tickets + " 票");
tickets--;
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} finally {
lock.unlock();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (tickets <= 0) {
System.out.println(Thread.currentThread().getName() + "--->售票结束!");
}
}
}
1号窗口--->售出第: 10 票
2号窗口--->售出第: 9 票
3号窗口--->售出第: 8 票
4号窗口--->售出第: 7 票
3号窗口--->售出第: 6 票
2号窗口--->售出第: 5 票
1号窗口--->售出第: 4 票
4号窗口--->售出第: 3 票
3号窗口--->售出第: 2 票
1号窗口--->售出第: 1 票
4号窗口--->售票结束!
2号窗口--->售票结束!
3号窗口--->售票结束!
1号窗口--->售票结束!
Process finished with exit code 0