线程的同步(解决多线程安全问题)
Posted 巧克力爱王子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程的同步(解决多线程安全问题)相关的知识,希望对你有一定的参考价值。
多线程出现安全问题的原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有 执行完,另一个线程参与进来执行。导致共享数据的错误。 解决方法: 对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以 参与执行。 Java对多线程的安全问题提供了专门的解决方法:同步机制。 方法一:同步代码块 synchronized //需要被同步的代码 说明: 1、操作共享数据的代码,即为需要被同步的代码(注意不要包含多了也不要包含少了); 2、共享数据:多个线程共同操作的变量; 3、同步监视器:俗称锁,任何一个类的对象都可以充当锁(要求各线程必须共用一把锁); 4、在实现Runnab接口创建多线程的方式中,可以考虑使用this作为同步监视器,在继承Thread类 创建多线程的方式中,可以考虑 类.class作为同步监视器。 下面是一个简单的多窗口卖票问题class Window implements Runnable//实现Runnable方法创建多线程
private static int ticket = 100;//票数
@Override
public void run() //重写run方法
while (true)
synchronized (this) //将操作共享数据的代码用synchronized包起来
if (ticket > 0)
//当前线程的名字
System.out.println(Thread.currentThread().getName() + ":买票,票号为:" + ticket);
ticket--;
else
break;
此时,对于操作共享数据的语句,只有当一个线程执行完了,释放了锁,其他线程才能进入。
方法二:使用同步方法
当操作共享数据的代码完全完整的声明在一个方法中,可以将此方法设置为同步的。
注意:
1、同步方法仍然涉及到同步监视器,只是不需要我们显示的声明;
2、非静态的同步方法,同步监视器为 this
静态的同步方法,同步监视器为当前类本身(类.class)
此为非静态的同步方法
//实现Runnable接口创建多线程
class Window1 implements Runnable
private static int ticket = 100;//票数
@Override
public void run() //重写run方法
while (true)
show();//该方法为操作共享数据的方法
private synchronized void show()//同步监视器为this
if (ticket > 0)
System.out.println(Thread.currentThread().getName() + ":买票,票号为:" + ticket);
ticket--;
此为静态的同步方法
//继承Thread类来创建多线程
class Window2 extends Thread
private static int ticket = 100;//票数
@Override
public void run()
while (true)
show();//该方法为操作共享数据的方法
private static synchronized void show()//同步监视器为Window2.class
if (ticket > 0)
System.out.println(Thread.currentThread().getName() + ":买票,票号为:" + ticket);
ticket--;
方式三:lock(锁)
class A private final ReentrantLock lock = new ReenTrantLock(); public void m() lock.lock(); try // 保证线程安全的代码 ; finally lock.unlock(); 说明: 1、从 JDK 5.0 开始, Java 提供了更强大的线程同步机制 —— 通过显式定义同步锁对象来实现同 步。同步锁使用Lock 对象充当; 2、 java.util.concurrent.locks.Lock 接口是控制多个线程对共享资源进行访问的 工具。锁提供了对共 享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得 Lock对象; 3、ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,在实现线 程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁。class Windowlock implements Runnable
private int trick = 100;
// 实例化ReentrantLock
private ReentrantLock lock = new ReentrantLock();
@Override
public void run()
while (true)
try
//调用锁定方法
lock.lock();
if(trick > 0)
System.out.println(Thread.currentThread().getName() + ":" + trick);
trick--;
else
break;
finally
//解锁
lock.unlock();
synchronized 与 lock的对比: 1. Lock是显式锁(手动开启和关闭锁,别忘记关闭锁), synchronized 是隐式锁,出了作用域自动 释放; 2. Lock只有代码块锁, synchronized 有代码块锁和方法锁; 3. 使用Lock 锁, JVM 将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更 多的子类) 优先使用顺序: lock——>同步代码块——>同步方法
以上是关于线程的同步(解决多线程安全问题)的主要内容,如果未能解决你的问题,请参考以下文章