`
geelong
  • 浏览: 119792 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

线程不安全的原因

阅读更多

 

package ThreadTest;

public class ThreadTest {
	public static void main(String args[]){
        MyThread mt = new MyThread() ;    // 定义线程对象
   
        Thread t1 = new Thread(mt) ;    // 定义Thread对象
        Thread t2 = new Thread(mt) ;    // 定义Thread对象
        Thread t3 = new Thread(mt) ;    // 定义Thread对象
        t1.start() ;
        t2.start() ;
        t3.start() ;
    }
}

class MyThread implements Runnable{
    private int ticket = 5 ;    // 假设一共有5张票
    public void run(){
//        synchronized (this){
        while(ticket>0){
       
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("卖票:ticket = " + ticket-- );
            }
//        }
    }
}

 

 

 

线程不安全条件

 

1 mt为一个对象实例

2 存在多个线程同时修改一个对象实例的属性,每个线程都有自己的临时空间用来保存对象实例的值,所以该值在被修改后不会马上同步到对象中,造成别的线程读到的不是对象实例最新的值,从而导致数据脏读,再造成脏写

 

运行结果如下

 

 

卖票:ticket = 5

卖票:ticket = 5

卖票:ticket = 4

卖票:ticket = 3

卖票:ticket = 2

卖票:ticket = 3

卖票:ticket = 1

卖票:ticket = 0

卖票:ticket = -1

 

 

 

修改:  同步代码块,使一个时间里,只有一个线程可以访问该代码。从而保证数据的修改是单线程同步的

 

 

class MyThread implements Runnable{
    private int ticket = 5 ;    // 假设一共有5张票
    public void run(){
        synchronized (this){
        while(ticket>0){
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("卖票:ticket = " + ticket-- );
            }
        }
    }
}


卖票:ticket = 5
卖票:ticket = 4
卖票:ticket = 3
卖票:ticket = 2
卖票:ticket = 1
 

        synchronized (this){

}

同步的是一个属性,而不是代码段(而this 代表了本类,即此时本类中的别的方法也被同步?

 

 

改进  用byte[] lock = {0}; 代替this. 比较省内存

 

class MyThread implements Runnable{
    private int ticket = 5 ;    // 假设一共有5张票
    private byte[] lock = {0};
    public void run(){
        synchronized (lock){
        while(ticket>0){
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("卖票:ticket = " + ticket-- );
            }
        }
    }
}

 

或者直接synchronized  多线程访问修改的属性  synchronized的是数组

 

class MyThread implements Runnable{
    private int[] ticket = {5} ;    // 假设一共有5张票
    public void run(){
    	synchronized(ticket){
    		sale();	
    	}
    }
    private void sale(){
    	 while(ticket[0]>0){
             try {
                 Thread.sleep(300);
             } catch (InterruptedException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
             System.out.println("卖票:ticket = " + ticket[0]-- );
         }
    }
}
 

 

2 同步方法

 

 

 

class MyThread implements Runnable{
    private  int ticket = 5 ;    // 假设一共有5张票
    public void run(){
    	sale();
    }
    private synchronized void sale(){
    	 while(ticket>0){
             try {
                 Thread.sleep(300);
             } catch (InterruptedException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
             System.out.println("卖票:ticket = " + ticket-- );
         }
    }
}
 

 

 

 

 

 

 

 

以下为线程安全的,但是继承Thread类后,资源(ticket )没有共享,各自卖各自的票。而实现runnable接口是可以资源共享的

 

package ThreadTest;

public class ThreadTestFirst {
	public static void main(String args[]){
		MyThreadF a = new MyThreadF("a");
		MyThreadF b = new MyThreadF("b");
		a.start();
		b.start();
    }
}

class MyThreadF extends Thread{
    private int ticket = 5 ;    // 假设一共有5张票
    private String name;
    public MyThreadF(String name) {
		this.name = name;
	}
    public void run(){
        while(ticket>0){
       
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(this.name  + "卖票:ticket = " + ticket-- );
            }
    }
}

 

 

a卖票:ticket = 5
b卖票:ticket = 5
b卖票:ticket = 4
a卖票:ticket = 4
b卖票:ticket = 3
a卖票:ticket = 3
b卖票:ticket = 2
a卖票:ticket = 2
a卖票:ticket = 1
b卖票:ticket = 1
 

 

分享到:
评论

相关推荐

    关于如何解决HashMap线程安全问题的介绍

    HashMap线程不安全的原因主要在于以下几个方面: 1. 多线程环境下并发修改:在多线程环境下,如果多个线程同时对HashMap进行读写操作,可能会导致数据的不一致性和数据丢失。例如,当一个线程正在执行put操作时,另...

    simpleDateFormat是线程不安全的

    `SimpleDateFormat`类的线程不安全主要源于以下几个原因: 1. **内部状态可变**:`SimpleDateFormat`内部维护了一些可变的状态,如解析和格式化日期时使用的日期字段和格式模板。当一个线程正在修改这些状态时,另...

    gethostbyname_r在某些linux版本中多线程不安全问题.pdf

    "gethostbyname_r在某些linux版本中多线程不安全问题" 在 Linux 操作系统中,gethostbyname_r 函数是一个常用的 DNS 解析函数,但是,在某些 Linux 版本中,这个函数存在多线程不安全问题。本文将详细介绍这个问题...

    CVI 线程锁、线程安全变量实例

    线程安全变量则可以确保在多线程环境下,即使不使用锁,也可以安全地更新和读取这些变量。 在LabWindows/CVI的`多线程_线程锁_线程安全变量`示例中,你可能会发现以下几个关键点: 1. **线程创建与销毁**:使用`...

    unix_linux线程安全问题

    在当今的计算机科学领域,线程作为操作系统调度的最小单元,它允许一个进程同时派生出多个线程。这些线程独立执行,共享进程资源...开发人员应当时刻铭记线程安全的重要性,并将其作为设计多线程程序时的首要考虑因素。

    浅议单例模式之线程安全(转)

    3. 懒汉式(线程不安全): 第一次调用getInstance()方法时才实例化,如果多线程环境下,可能导致多个实例。 ```java public class Singleton { private static Singleton INSTANCE; private Singleton() {} ...

    java线程线程安全同步线程

    线程安全和同步线程是确保在多线程环境下正确执行的关键因素。线程安全指的是一个方法或类在多线程环境下可以正确无误地运行,不会因为线程之间的交互而导致数据的不一致或错误。同步线程则是指通过特定机制(如锁)...

    线程安全的单例模式

    综上所述,线程安全的单例模式实现是一个复杂的过程,需要综合考虑效率和线程安全两方面的因素。通过上述几种不同的实现方式,我们可以根据实际需求选择最适合的一种。其中,双重检查锁定因其较高的性能和线程安全性...

    Java多线程-线程的安全问题与线程的同步机制介绍

    Java多线程-线程的安全问题与线程的同步机制介绍 在 Java 多线程编程中,线程安全问题是非常重要的一个话题。...通过了解线程安全问题的原因和解决方案,可以更好地编写多线程程序,避免线程安全问题的出现。

    【并发】为什么HashMap是线程不安全的?

    经常会看到说HashMap是线程不安全的,ConcurrentHashMap是线程安全的等等说法,不禁有个疑问,什么是线程安全?什么样的类是线程安全的? 1.什么是线程安全性(what) 线程安全定义,最核心是正确性, 正确性:多个...

    C++线程安全问题及解决方法,C++智能指针

    内容概要:文章内容从原子性、可见性、有序性三个方面介绍C++线程安全问题的原因。通过原子操作、线程同步如互斥锁、读写锁、条件变量、信号量等方法解决C++线程安全问题。同时介绍了线程安全的单例,饿汉模式和懒汉...

    线程安全总结.doc

    本文档旨在从基础概念出发,详细介绍导致线程不安全的原因、如何避免线程不安全现象的发生,并提供具体的示例代码。 #### 基础概念 1. **线程(Thread)** - 线程是程序执行流的基本单位,是操作系统调度的最小...

    java多线程安全性基础介绍.pptx

    java多线程安全性基础介绍 线程安全 正确性 什么是线程安全性 原子性 竞态条件 i++ 读i ++ 值写回i 可见性 JMM 由于cpu和内存加载速度的差距,在两者之间增加了多级缓存导致,内存并不能直接对cpu可见。 ...

    线程安全队列Queue

    在开发多线程应用时,线程安全成为至关重要的考量因素之一。特别是在需要处理并发任务时,如何确保线程之间的安全通信变得尤为重要。本篇文章将围绕一个具体的场景——项目中的巡检任务管理——深入探讨如何利用`...

    struts1,struts2,webwork,线程安全问题

    - **线程安全问题原因:** - 因为同一个`Action`实例会被不同的HTTP请求重用,所以如果`Action`类中有成员变量(除了`transient`变量),那么这些成员变量就可能成为线程安全的问题点。 - 如果在`Action`类中定义...

    线程安全的jdbc连接池

    在Java编程中,数据库操作是不可或缺的一部分,而有效管理数据库连接是提高系统性能的关键因素。线程安全的JDBC连接池就是为此目的设计的一种优化手段。在这个简单的实现中,我们利用了`ConcurrentLinkedQueue`数据...

    JAVA实现一个线程安全的循环单链表

    在Java编程语言中,线程安全是多线程环境下编程时必须考虑的重要因素。线程安全的循环单链表是一种高效的数据结构,它允许在并发环境中进行插入、删除和遍历操作而不会出现数据不一致的情况。这篇博客文章将探讨如何...

    浅谈Java StringBuilder为什么线程不安全

    浅谈Java StringBuilder为什么线程不安全 Java StringBuilder是一个可变的字符串对象,它可以动态地增加或删除字符,然而,它却不是线程安全的。在多线程环境下,使用StringBuilder可能会出现一些问题,例如输出值...

    C#内存释放-线程控制-线程启动-线程暂停

    这就是使用后台线程的原因,比如使用`BackgroundWorker`组件或自定义线程。WFormsThread可能是一个示例,展示了如何在Windows Forms中正确处理线程,同时确保UI的响应性。 总结一下,本主题涵盖了C#中的线程控制...

    QT中sqlite多线程操作4个注意问题

    SQLite本身并不提供完全的线程安全,这意味着在不同线程中并发访问数据库时,需要开发者自己处理同步问题。在Qt中,可以使用QMutex或QReadWriteLock等同步原语来保护对数据库的访问。 2. **数据库连接**: 每个...

Global site tag (gtag.js) - Google Analytics