`
geelong
  • 浏览: 115187 次
  • 性别: 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是线程不安全的,ConcurrentHashMap是线程安全的等等说法,不禁有个疑问,什么是线程安全?什么样的类是线程安全的? 1.什么是线程安全性(what) 线程安全定义,最核心是正确性, 正确性:多个...

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

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

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

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

    c_safe_lib:c数据结构线程安全库

    c_safe_lib c线程安全库,这个项目的目的是创造一套可以工程使用的c数据结构库,在实际工程中一套优秀高效的数据结构库是必不可少的。主要解决俩个方面:1.线程安全2.跨平台 linux 、windows实现原理功能状态实现原理...

    Qt 多线程及简单实例 demo

    1.多线程的执行顺序无法保证,与操作系统的调度策略和线程优先级等因素有关。 2.多线程的切换可能发生在任何时刻、任何地点。 3.多线程对代码的敏感度高,因此对代码的细微修改都可能产生意想不到的效果。 先由一...

    C#多线程编程实战 源代码

    在计算机处理器发展为包含越来越多的核心的时期,多线程是创建可伸缩性、高效的、高响应性应用程序的关键因素。如果你没有正确地使用多线程,它会导致难以捉摸的问题,需要你花费大量时间去解决。因此,现代应用程序...

    多线程计数,怎么保持计数准确

    首先使用设计模式中的单件模式,防止多次初始化对象,...此程序会增加三次运算,原因是本线程未到200次,但是必然会有一个线程第一次增加所以在add里再做判断 http://blog.csdn.net/ggbb190/article/details/18003165

    多线程使用原因以及例程

    关于多线程技术的精华总结,从创建到具体如何应用以及使用多线程的原因及其价值,适合初学者快速理解这部分内容以及开发具体的程序。

    Java线程CPU占用高原因排查方法

    Java线程CPU占用高原因排查方法,Java线程CPU占用高原因排查方法

    Linux系统编程之线程同步

    线程同步,指一个线程发出某一功能调用时,在没有得到结果之前,该调用不返回。同时其它线程为保证数据一致性,不能调用该功能。 举例1: 银行存款 5000。柜台,折:取3000;提款机,卡:取 3000。剩余:2000 举例2...

    线程问题出现与解决

    线程问题总结:多线程实现方式、线程控制、多线程安全问题以及解决方法、单例懒汉式的线程安全问题、死锁出现的原因

    VB创建线程动态链接库(VBCreateThread.dll)

    编写原因:鉴于VB创建稳定线程的需求 特点:可替代API CreateThread来创建线程,且自动对线程进行初始化,线程函数中不再需要初始化线程就可以使用对象、类、窗口等。提供多达四个线程参数,如果不够用的可通过...

    远程线程插入

    木马远程线程插入,进行对电脑的远程控制,从而控制别人电脑,对于杀毒软件可以检测并结束其进程

    C++线程安全的单例模式

     需要用锁,来保证其线程安全性:原因:多个线程可能进入判断是否已经存在实例的if语句,从而non thread safety.  使用double-check来保证thread safety.但是如果处理大量数据时,该锁才成为严重的性能瓶颈。 ...

    ThreadLocal:如何优雅的解决SimpleDateFormat多线程安全问题

    目录SimpleDateFormat诡异bug复现SimpleDateFormat诡异bug字符串日期转Date日期(parse)Date日期转String类型(format)SimpleDateFormat出现bug的原因如何解决SimpleDateFormat多线程安全问题局部变量使用...

    java并发编程:线程基础

    线程的同步与阻塞: 引入多线程访问共享资源可能导致的问题,如竞态条件和数据不一致。介绍如何使用 synchronized 关键字来实现线程的同步和阻塞。 线程间通信: 详解线程间通信的方法,包括 wait、notify 和 ...

    多线程死锁

    明白死锁产生的原因,在程序中演示死锁产生并从而实现多线程陈旭解决死锁(deadlock)这一类问题。

    C#用了多线程界面卡死

    C#用了多线程界面卡死

    java的hashMap多线程并发情况下扩容产生的死锁问题解决.docx

    这就有可能导致A线程和B线程同时对一个数组扩容,A线程扩容后替换掉老数组,这时B线程使用的数组实际上是A线程扩容后的数组,就会产生线程安全问题。 死锁原因 比如,当前集合数组长度为2,已经有两个元素被放在了...

    C++基于消息队列的多线程实现示例代码

    实现消息队列的关键因素是考量不同线程访问消息队列的同步问题。本实现涉及到几个知识点 std::lock_guard 介绍 std::lock_gurad 是 C++11 中定义的模板类。定义如下: template <class> class lock_guard; lock_...

Global site tag (gtag.js) - Google Analytics