java实现线程同步的三种方法,保证线程安全
实现同步的三种方法
多线程共享数据时,会发生线程不安全的情况,多线程共享数据必须同步。 实现同步的三种方法:
- 使用同步代码块
- 使用同步方法
- 使用互斥锁ReetrantLock(更灵活的代码控制)
锁:同步监视器,可以任意一个对象,通常可以收用共享对象作为锁,this,还可以准备任意一个不变的对象(没有业务逻辑,只作为锁) 同步代码块的执行过程: 1.第一个线程来到,发现有锁,但是是open的状态,进去执行,同时将状态修改为close; 2.第一个线程可能在执行过程中释放CPU资源,进入阻塞状态,但是不会开锁; 3.第二个线程获取CPU资源,发现有锁,状态为close,第二个线程也阻塞; 4.第一个线程重新获取CPU资源,继续执行后续的代码,执行结束,出来,修改状态为open; 5.第二个线程又获取CPU资源,重复第一个线程的操作; ... 同步的优缺点: 优点:保证了线程安全 缺点:降低了效率
import java.util.concurrent.locks.ReentrantLock; public class SyncThreadDemo { public static void main(String[] args) { MyRunnable mr = new MyRunnable(); new Thread(mr).start(); new Thread(mr).start(); } } class MyRunnable implements Runnable { private int tickts = 10; @Override public void run() { for (int i = 0; i < 100; i++) { // if (tickts > 0) { //方法一:使用同步代码块,其中this指代共享对象tickts,甚至可以是new 出来的自己实的一个不变类就如Account.java //共享用户,作为锁 //private Account account = new Account(); //synchronized (account) { // synchronized (this) { // System.out.println("第" + (tickts--) + "张票售出"); // try { // Thread.sleep(100); // } catch (InterruptedException e) { // e.printStackTrace(); // } // } // } // 方法二:使用同步方法达到线程安全 saleTickts(); // 方法三:使用ReentrantLock,更加灵活,可以加入判断,在特定的情况下释放锁 saleTickts2(); }// for } // 同步方法:同步的是当前对象 private synchronized void saleTickts() { if (tickts > 0) { System.out.println("第" + (tickts--) + "张票售出"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } }// saleTickts ReentrantLock lock = new ReentrantLock(); // 方法三:使用ReentrantLock,更加灵活,可以加入判断,在特定的情况下释放锁 private void saleTickts2() { lock.lock(); try { if (tickts > 0) { System.out.println("第" + (tickts--) + "张票售出"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } // 保证锁一定会被释放,不会出现死锁情况 } finally { lock.unlock();// 释放锁 } }// saleTickts2 }