Java线程安全问题代码实现

解决线程安全问题的第一种方案:使用同步代码块

格式:

  synchronized(锁对象) {

    可能会出现线程安全问题的代码(访问了共享数据的代码)

  }

注意:代码块中的锁对象,可以是任意对象,但必须保证多个线程之间使用的是同一个

锁对象的作用是把同步代码块锁住,同一时间只能让一个线程在同步代码块中执行

package com.fgy.demo02;

/**
 * 实现卖票案例
 */
public class RunnableImpl implements Runnable {
    private int ticket = 100;
    Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (obj) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在买第" + ticket + "张票");
                    ticket--;
                }
            }
        }
    }
}
package com.fgy.demo02;

public class Demo01Ticket {
    public static void main(String[] args) {
        RunnableImpl run = new RunnableImpl();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }
}

解决线程安全问题的第二种方案:使用同步方法

使用步骤:

   1.把访问了共享数据的代码抽取出来,放到一个方法中

   2.在方法上添加synchronized修饰符

格式:

  修饰符 synchronized 返回值类型 方法名(...) {

    可能会出现线程安全问题的代码(访问了共享数据的代码)

  }

同步方法的锁对象是:this

静态同步方法的锁对象不能是this,因为this是创建对象后产生的,静态方法优先于对象

静态方法的锁对象是本类的class文件对象

package com.fgy.demo03;

/**
 * 实现卖票案例
 */
public class RunnableImpl implements Runnable {
    private int ticket = 100;

    @Override
    public void run() {
        while (true) {
            payTicket();
        }
    }

    public synchronized void payTicket() {
        if (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "正在买第" + ticket + "张票");
            ticket--;
        }
    }
}

解决线程安全问题的第三种方案:使用lock锁

使用步骤:

   1.在成员位置创建ReenterantLock对象

   2.在可能出现安全问题的代码前调用Lock接口中的方法lock()获取锁

   3.在可能出现安全问题的代码后调用Lock接口中的方法unlock()释放锁

package com.fgy.demo04;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 实现卖票案例
 */
public class RunnableImpl implements Runnable {
    private int ticket = 100;
    Lock l = new ReentrantLock();

    /*@Override
    public void run() {
        while (true) {
            l.lock();

            if (ticket > 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "正在买第" + ticket + "张票");
                ticket--;
            }

            l.unlock();
        }
    }*/

    @Override
    public void run() {
        while (true) {
            l.lock();

            if (ticket > 0) {
                try {
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName() + "正在买第" + ticket + "张票");
                    ticket--;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // 无论程序是否发生异常都会释放锁
                    l.unlock();
                }
            }
        }
    }
}

原文地址:https://www.cnblogs.com/roadlandscape/p/12105131.html

时间: 2024-10-17 01:52:40

Java线程安全问题代码实现的相关文章

java线程安全问题之静态变量、实例变量、局部变量

Java多线程编程中,存在很多线程安全问题,至于什么是线程安全呢,给出一个通俗易懂的概念还是蛮难的,如同<java并发编程实践>中所说: 写道 给线程安全下定义比较困难.存在很多种定义,如:"一个类在可以被多个线程安全调用时就是线程安全的". 此处不赘述了,首先给出静态变量.实例变量.局部变量在多线程环境下的线程安全问题结论,然后用示例验证,请大家擦亮眼睛,有错必究,否则误人子弟! 静态变量:线程非安全. 静态变量即类变量,位于方法区,为所有对象共享,共享一份内存,一旦静态

(转)java线程安全问题之静态变量、实例变量、局部变量

java多线程编程中,存在很多线程安全问题,至于什么是线程安全呢,给出一个通俗易懂的概念还是蛮难的,如同<java并发编程实践>中所说: 写道 给线程安全下定义比较困难.存在很多种定义,如:“一个类在可以被多个线程安全调用时就是线程安全的”. 此处不赘述了,首先给出静态变量.实例变量.局部变量在多线程环境下的线程安全问题结论,然后用示例验证,请大家擦亮眼睛,有错必究,否则误人子弟! 静态变量:线程非安全. 静态变量即类变量,位于方法区,为所有对象共享,共享一份内存,一旦静态变量被修改,其他对象

java线程安全问题原理性分析

1.什么是线程安全问题? 从某个线程开始访问到访问结束的整个过程,如果有一个访问对象被其他线程修改,那么对于当前线程而言就发生了线程安全问题:如果在整个访问过程中,无一对象被其他线程修改,就是线程安全的. 2.线程安全问题产生的根本原因 首先是多线程环境,即同时存在有多个操作者,单线程环境不存在线程安全问题.在单线程环境下,任何操作包括修改操作都是操作者自己发出的,操作者发出操作时不仅有明确的目的,而且意识到操作的影响. 多个操作者(线程)必须操作同一个对象,只有多个操作者同时操作一个对象,行为

Java线程池代码实现

package com.fgy.demo07; public class RunnableImpl implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() + "创建了一个新的线程"); } } package com.fgy.demo07; public class ExtendsThread extends Thread { @Ov

java 线程安全问题

public class ThreadA implements Runnable{ public static int number; public String test; @Override public void run() { while(true){ try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } } } number是共享资源,属于非线程安全,test属于线程

Java线程池Executors.newFixedThreadPool原理解析

从事Java多线程开发的程序员来说,了解Java的线程池实现原理是必不可少的,以下将会结合Java线程池代码来说明它的实现原理,首先,我们要思考: 线程池的表现形式 线程池里面的线程什么时候创建 线程池里面的线程什么时候结束或者该不该结束 线程池的实现原理 说道Java线程池就不得不说ExecutorService接口和Executors类了,从源码上来看Executors类里面封装了线程池的创建,并且定义了各自不同的线程池类型,本文着重讲Executors这个类的newFixedThreadP

浅谈利用同步机制解决Java中的线程安全问题

我们知道大多数程序都不会是单线程程序,单线程程序的功能非常有限,我们假设一下所有的程序都是单线程程序,那么会带来怎样的结果呢?假如淘宝是单线程程序,一直都只能一个一个用户去访问,你要在网上买东西还得等着前面千百万人挑选购买,最后心仪的商品下架或者售空......假如饿了吗是单线程程序,那么一个用户得等前面全国千万个用户点完之后才能进行点餐,那饿了吗就该倒闭了不是吗?以上两个简单的例子,就说明一个程序能进行多线程并发访问的重要性,今天就让我们去了解一下Java中多线程并发访问这个方向吧. **第一

关于java Servlet,Struts,springMVC 的线程安全问题

现在主流的java的前端框架有:struts1,struts2,springmvc 还有最根本的servlet; 前些天一个朋友问我这方面的问题,就研究一番: 1.关于struts1: Struts1使用的ActionServlet是单例的,由这一个servlet处理所有.do请求.RequestProcessor也是单例. RequestProcessor的processActionCreate方法: /**   * <p>Return an <code>Action</c

java 22 - 12 多线程之解决线程安全问题的实现方式1

从上一章知道了多线程存在着线程安全问题,那么,如何解决线程安全问题呢? 导致出现问题的原因: A:是否是多线程环境 B:是否有共享数据 C:是否有多条语句操作共享数据 上一章的程序,上面那3条都具备,所以肯定出问题. 如何解决问题: 原因A.B肯定不能改变,所以只能改变原因C 解决问题思路: 如果把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行这个整体的时候,别的线程不能执行. 这时候就用到了java提供的:同步机制 同步代码块: synchronized(对象){  需要同步的代码