目录
1、什么是线程安全
当服务器运行一个项目时,相当于开启了一个进程。这个进程下包含着一个或多个线程并发执行,这些线程共享进程独立占用内存空间、资源。这时可能会遇到多个线程同时访问同一个对象,并且线程可以对该对象中的数据进行更改,若是不实现线程同步,就可能会造成脏数据,因此需要保证线程同步。线程同步表示在任意时间内都只能有一个线程或没有线程访问目标对象。
2、实现线程安全的方法
java语言提供两种方式实现线程:
(1)一种是通过synchronized关键字修饰。
(2)另外一种是通过实现lock接口,利用lock获取线程锁、unlock释放线程锁。
Lock:Lock是用于实现线程安全的一种接口,其用法较于synchronized要灵活得多。
常用方法有:
lock():用于获取资源线程锁;
unlock():用于释放资源线程锁;
writeLock():获取写锁;
readLock():获取读锁;
tryLock():判断资源线程锁是否被占用,返回true\false
3、实现案例
(1)synchronized修饰方法
public class test {
ticket ticket=new ticket();
public synchronized void buyTicket(String threadName){
ticket.list.add(threadName+"买了1张票");
ticket.theTicketNumber=ticket.theTicketNumber+1;
}
public synchronized void returnTicket(String threadName){
ticket.list.add(threadName+"退了1张票");
ticket.theTicketNumber=ticket.theTicketNumber-1;
}
@Test
public void main() throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
for (int i=1;i<=3;i++){
buyTicket("窗口1");
}
}
},"窗口1").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=1;i<=3;i++){
buyTicket("窗口2");
}
}
},"窗口2").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=1;i<=3;i++){
returnTicket("窗口3");
}
}
},"窗口3").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=1;i<=3;i++){
returnTicket("窗口4");
}
}
},"窗口4").start();
Thread.sleep(3000);
for (String str:ticket.list){
System.out.println(str);
}
System.out.println(ticket.theTicketNumber);
}
}
class ticket{
List<String> list=new ArrayList<>();
int theTicketNumber=0;
}
(2)synchronized关键字修饰代码段
public class test { ticket ticket=new ticket(); public void buyTicket(String threadName){ synchronized (ticket){ ticket.list.add(threadName+"买了1张票"); ticket.theTicketNumber=ticket.theTicketNumber+1; } } public void returnTicket(String threadName){ synchronized (ticket){ ticket.list.add(threadName+"退了1张票"); ticket.theTicketNumber=ticket.theTicketNumber-1; } } @Test public void main() throws InterruptedException { new Thread(new Runnable() { @Override public void run() { for (int i=1;i<=3;i++){ buyTicket("窗口1"); } } },"窗口1").start(); new Thread(new Runnable() { @Override public void run() { for (int i=1;i<=3;i++){ buyTicket("窗口2"); } } },"窗口2").start(); new Thread(new Runnable() { @Override public void run() { for (int i=1;i<=3;i++){ returnTicket("窗口3"); } } },"窗口3").start(); new Thread(new Runnable() { @Override public void run() { for (int i=1;i<=3;i++){ returnTicket("窗口4"); } } },"窗口4").start(); Thread.sleep(3000); for (String str:ticket.list){ System.out.println(str); } System.out.println(ticket.theTicketNumber); } } class ticket{ List<String> list=new ArrayList<>(); int theTicketNumber=0; }
(3)通过lock接口实现线程同步
public class test { ticket ticket=new ticket(); Lock lock= new ReentrantLock(); public void buyTicket(String threadName){ try { lock.lock(); ticket.list.add(threadName+"买了1张票"); ticket.theTicketNumber=ticket.theTicketNumber+1; } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } public void returnTicket(String threadName){ try { lock.lock(); ticket.list.add(threadName+"退了1张票"); ticket.theTicketNumber=ticket.theTicketNumber-1; } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } @Test public void main() throws InterruptedException { new Thread(new Runnable() { @Override public void run() { for (int i=1;i<=3;i++){ buyTicket("窗口1"); } } },"窗口1").start(); new Thread(new Runnable() { @Override public void run() { for (int i=1;i<=3;i++){ buyTicket("窗口2"); } } },"窗口2").start(); new Thread(new Runnable() { @Override public void run() { for (int i=1;i<=3;i++){ returnTicket("窗口3"); } } },"窗口3").start(); new Thread(new Runnable() { @Override public void run() { for (int i=1;i<=3;i++){ returnTicket("窗口4"); } } },"窗口4").start(); Thread.sleep(3000); for (String str:ticket.list){ System.out.println(str); } System.out.println(ticket.theTicketNumber); } } class ticket{ List<String> list=new ArrayList<>(); int theTicketNumber=0; }
4、执行效果图(三次统一)
至此完毕!