线程安全问题的例子以及解决方案示例代码
1.多线程安全问题,出现重复卖票的现象
package net.bbd.spider.lock; public class Ticket implements Runnable { static Integer tickets = 10; @Override public void run() { while(tickets > 0) { if (tickets <= 0) { return; } System.out.println(Thread.currentThread().getName()+"--->售出第: "+tickets+" 票"); tickets--; try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } if (tickets <= 0) { System.out.println(Thread.currentThread().getName()+"--->售票结束!"); } } } public static void main(String[] args) { Ticket ticket = new Ticket(); new Thread(ticket,"线程名称" + 1).start(); new Thread(ticket,"线程名称" + 2).start(); new Thread(ticket,"线程名称" + 3).start(); new Thread(ticket,"线程名称" + 4).start(); } }
2.使用synchronized关键字做线程安全控制
package net.bbd.spider.lock; public class TicketSyn implements Runnable { static Integer tickets = 10; @Override public void run() { while(tickets > 0) { synchronized (this) { if (tickets <= 0) { return; } System.out.println(Thread.currentThread().getName()+"--->售出第: "+tickets+" 票"); tickets--; try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } if (tickets <= 0) { System.out.println(Thread.currentThread().getName()+"--->售票结束!"); } } } public static void main(String[] args) { TicketSyn ticket = new TicketSyn(); new Thread(ticket,"线程名称" + 1).start(); new Thread(ticket,"线程名称" + 2).start(); new Thread(ticket,"线程名称" + 3).start(); new Thread(ticket,"线程名称" + 4).start(); } }
3.使用ReentrantLock对象做线程安全控制
package net.bbd.spider.lock; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TicketReentrantLock implements Runnable { static Integer tickets = 10; Lock lock = new ReentrantLock();
@Override public void run() { //System.out.println(Thread.currentThread().getName()+"--->锁锁锁: " + lock); // Lock锁机制 while(tickets > 0) { try { lock.lock(); if (tickets <= 0) { return; } System.out.println(Thread.currentThread().getName()+"--->售出第: " + tickets + " 票"); tickets--; } catch (Exception e1) { e1.printStackTrace(); }finally { lock.unlock(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } if (tickets <= 0) { System.out.println(Thread.currentThread().getName()+"--->售票结束!"); } } public static void main(String[] args) { TicketReentrantLock ticket = new TicketReentrantLock(); new Thread(ticket,"线程名称" + 1).start(); new Thread(ticket,"线程名称" + 2).start(); new Thread(ticket,"线程名称" + 3).start(); new Thread(ticket,"线程名称" + 4).start(); } }
4.使用写锁ReentrantReadWriteLock做线程安全控制
package net.bbd.spider.lock; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class TicketWriteLock implements Runnable { static Integer tickets = 10; ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); Lock writeLock = readWriteLock.writeLock();
@Override public void run() { // System.out.println(Thread.currentThread().getName()+"--->锁锁锁: " + writeLock); // Lock锁机制 while(tickets > 0) { try { writeLock.lock(); if (tickets <= 0) { return; } System.out.println(Thread.currentThread().getName()+"--->售出第: " + tickets + " 票"); tickets--; } catch (Exception e1) { e1.printStackTrace(); }finally { writeLock.unlock(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } if (tickets <= 0) { System.out.println(Thread.currentThread().getName()+"--->售票结束!"); } } public static void main(String[] args) { TicketWriteLock ticket = new TicketWriteLock(); new Thread(ticket,"线程名称" + 1).start(); new Thread(ticket,"线程名称" + 2).start(); new Thread(ticket,"线程名称" + 3).start(); new Thread(ticket,"线程名称" + 4).start(); } }