你知道java的线程安全应该如何去实现吗?java线程安全的实现方式又有哪些呢?下面就和小编一起来看看具体的实现方法吧!
一个程序在运行起来的时候,会转换成进程,一般来说,会含有很多个线程。
一般的情况下,在一个进程当中,那些比较费时的操作,经常会采用多线程来进行解决。
例如:
生活当中经常可见的银行取钱、售票等,经常就会涉及到并发的问题,那么这个时候,往往就要用到多线程技术。
在进程当中,有多个并发线程进入一个重要数据的代码块的时候,在修改数据的过程当中,有很大的可能会引发线程安全的问题,从而引起了数据异常。
那么下面以售票问题作为例子,来演示线程安全的问题。
首先,在不对多线程数据进行保护的情况下会引发出来的状况
public class ThreadUnSecurity { static int tickets = 10; 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 ThreadUnSecurity().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 票 3号窗口--->售出第: 10 票 2号窗口--->售出第: 10 票 4号窗口--->售出第: 10 票 2号窗口--->售出第: 6 票 1号窗口--->售出第: 5 票 3号窗口--->售出第: 4 票 4号窗口--->售出第: 3 票 2号窗口--->售出第: 2 票 4号窗口--->售出第: 1 票 1号窗口--->售出第: 1 票 3号窗口--->售票结束! 2号窗口--->售票结束! 1号窗口--->售票结束! 4号窗口--->售票结束!
这个时候,我们可以看出,同一张票在不对票数进行保护的时候,会出现同一张票会被售出多次的情况。
因为线程调度中的不确定性,所以在演示上面的代码的时候,出现的运行结果会有不同。
1、实现线程安全的方式
同步代码块
package com.bpan.spring.beans.thread; import com.sun.org.apache.regexp.internal.recompile; public class ThreadSynchronizedSecurity { static int tickets = 10; class SellTickets implements Runnable{ @Override public void run() { // 同步代码块 while(tickets > 0) { synchronized (this) { // System.out.println(this.getClass().getName().toString()); if (tickets <= 0) { return; } System.out.println(Thread.currentThread().getName()+"--->售出第: "+tickets+" 票"); tickets--; try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } if (tickets <= 0) { System.out.println(Thread.currentThread().getName()+"--->售票结束!"); } } } } public static void main(String[] args) { SellTickets sell = new ThreadSynchronizedSecurity().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(); } }
输出的结果可以自行调试。
2、实现线程安全的方式
同步方法
package com.bpan.spring.beans.thread; public class ThreadSynchroniazedMethodSecurity { static int tickets = 10; class SellTickets implements Runnable{ @Override public void run() { //同步方法 while (tickets > 0) { synMethod(); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (tickets<=0) { System.out.println(Thread.currentThread().getName()+"--->售票结束"); } } } synchronized void synMethod() { synchronized (this) { if (tickets <=0) { return; } System.out.println(Thread.currentThread().getName()+"---->售出第 "+tickets+" 票 "); tickets-- ; } } } public static void main(String[] args) { SellTickets sell = new ThreadSynchroniazedMethodSecurity().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(); } }
输出结果可以自行调试。
3、实现线程安全的方式
Lock锁机制,通过创建Lock对象,采用lock()加锁,unlock()解锁,来保护指定的代码块
package com.bpan.spring.beans.thread; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ThreadLockSecurity { static int tickets = 10; 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()+"--->售票结束!"); } } } public static void main(String[] args) { SellTickets sell = new ThreadLockSecurity().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(); } }
以上的三种实现线程安全的方式你都了解了吗?更多相关知识,可以继续关注奇Q工具网的java架构师栏目来了解呢!
推荐阅读: