多线程-线程安全问题

1.多线程-线程安全问题演示

多个线程对象运行同一个线程任务代码的时候,一个线程运行到判断语句后被临时阻塞了,下个线程继续判断,直接输出结果,前一个线程再输出的结果,可能会出问题

class Ticket implements Runnable{
    private int num = 100;
    public void run(){
        while(true){
            if(num>0){
                try{
                    Thread.sleep(10);
                }catch(InterruptedException e){}
                 //让线程在这里小睡,导致了 0 -1 等错误票的产生。
                  //出现了线程安全问题。
                System.out.println(Thread.currentThread().getName()+"..sale:"+num--);
            }
        }
    }
}
class ThreadDemo3_Ticket_Runnable{
    public static void main(String[] args) {
        Ticket t = new Ticket();
         
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        Thread t4 = new Thread(t);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        //多个线程对象调用同一个线程任务
    }
}

2.多线程-线程安全问题原因

原因:

1.多个线程在同时处理共享数据。

2.线程任务中的有多条代码在操作共享数据。

安全问题成因就是:一个线程在通过多次操作共享数据的过程中,其他线程参与了共享数据的操作。

导致到了数据的错误.

想要知道你的多线程程序有没有安全问题:

只要看线程任务中是否有多条代码在处理共享数据。

3.多线程-线程安全问题-同步代码块解决

解决:

一个线程在通过多条语句操作共享数据的过程中,不允许其他线程参与运算。

如何代码体现呢?

Java中提供了同步代码块进行引起安全问题的代码封装。

格式:

synchronized(对象) //该对象是任意的
{
    //需要被同步的代码;
}
class Ticket implements Runnable{
    private int num = 100;
    Object obj = new Object();
    public void run(){
        while(true){
            synchronized(obj){
                if(num>0){
                    try{
                        Thread.sleep(10);
                    }catch(InterruptedException e){}
                                                
                    System.out.println(Thread.currentThread().getName()+"..sale:"+num--);
                }
            }
        }
    }
}
 
class ThreadDemo4_Ticket_Safe{
    public static void main(String[] args) {
        Ticket t = new Ticket();
         
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        Thread t4 = new Thread(t);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

4.多线程-线程安全问题-同步代码块好处&弊端&前提

同步好处:解决了多线程的安全问题。

同步弊端:降低了效率。

同步的前提:

1.至少有两个线程在同步中。

2.必须保证同步使用的是同一个锁。

synchronized(new Object()){

}

意思是让每个线程进到同步代码块中,就会换一把新锁。有安全隐患,没有保障多线程直接使用用一把锁。

5.多线程-线程安全问题-同步函数使用的锁

同步的第二种表现形式:同步函数。

问题:同步函数使用的锁是什么呢?

同步函数使用的锁,应该是this。

同步函数和同步代码块的区别?

同步函数使用的固定锁this。

同步代码块使用的锁是可以指定的。

class Ticket implements Runnable{
    private int num = 100;
    boolean flag = true;
    Object obj = new Object();
    public void run(){
        if(flag){
            while(true){
                synchronized(this){
                    if(num>0){
                        try{Thread.sleep(10);}catch(InterruptedException e){}
                        System.out.println(Thread.currentThread().getName()+"..obj:"+num--);
                     }
                }
            }
        }else{
            while(true){
                this.sale();
            }
        }
    }
     
    public synchronized void sale(){//同步函数。
        if(num>0){
            try{Thread.sleep(10);}catch(InterruptedException e){}
            System.out.println(Thread.currentThread().getName()+"..func:"+num--);
        }
    }
}
class ThreadDemo5_Ticket_SynFunction{
    public static void main(String[] args){
        Ticket t = new Ticket();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        t1.start();
        try{Thread.sleep(10);}catch(InterruptedException e){}
        t.flag = false;
        t2.start();
    }
}

6.多线程-线程安全问题-静态同步函数使用的锁

静态同步函数使用的锁是什么?

就是所在类的  类名.class   字节码文件对象。

class Ticket implements Runnable{
    private static  int num = 100;
    boolean flag = true;
    public void run(){
        if(flag){
            while(true){
                synchronized(Ticket.class)//super.getClass(){
                if(num>0){
                    try{Thread.sleep(10);}catch(InterruptedException e){}
                    System.out.println(Thread.currentThread().getName()+"..obj:"+num--);
                }
            }
        }else{
            while(true) {
                this.sale();
            } 
        }   
    }

 
    public static synchronized  void sale(){//static同步函数。
        if(num>0){
            try{Thread.sleep(10);}catch(InterruptedException e){}
            System.out.println(Thread.currentThread().getName()+"..func:"+num--);
        }
     }
 }
 
class ThreadDemo5_Ticket_StaticLock{
    public static void main(String[] args) {
        Ticket t = new Ticket();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        t1.start();
        try{Thread.sleep(10);}catch(InterruptedException e){}
        t.flag = false;
        t2.start();
    }
}

7.多线程-线程安全问题-单例懒汉式多线程问题

//饿汉式,不会出现线程安全问题,没有多条共享数据
class Single1{
    private static final Single1 s = new Single1();
    private Single1(){}
    public static Single1 getInstance(){
        return s;
    }
}
 
 
 
//懒汉式
 
/*
加同步关键字,解决的是安全问题。
public static  Single getInstance() {if(s==null)  {s = new Single();} }
加双重判断,是为了提高效率,不用每次都进入同步代码块。 
*/
class Single2{
    private static Single2 s = null;
    private Single2(){}
    public static  Single2 getInstance(){
        //当存在对象时,执行到第一个if语句判断条件不符合后,不用进入下面的同步代码块
        if(s==null){    
            synchronized(Single.class){
                if(s==null){
                    s = new Single();
                }
            }
        }
        return s;
    }
}

14-多线程-线程安全问题-死锁示例

 
class Demo implements Runnable{
    private boolean flag;
    
    Demo(boolean flag){
        this.flag = flag;
    }
     
    public void run(){
        if(flag){
            while(true){
                synchronized(MyLock.LOCKA){
                    System.out.println("if locka");
                    synchronized(MyLock.LOCKB){
                        System.out.println("if lockb");
                    }
                }
            }
        }else{
            while(true){
                synchronized(MyLock.LOCKB){
                    System.out.println("else lockb");
                    synchronized(MyLock.LOCKA){
                        System.out.println("else locka");
                    }
                }
            }
        }
    }
}
 
 
class MyLock{
    public static final Object LOCKA = new Object();
    public static final Object LOCKB = new Object();
}
 
 
class ThreadDemo8_DeadLock {
    public static void main(String[] args) {
        Demo d1 = new Demo(true);
        Demo d2 = new Demo(false);
        Thread t1 = new Thread(d1);
        Thread t2 = new Thread(d2);
        t1.start();
        t2.start();
    }
}
时间: 2024-08-07 17:00:17

多线程-线程安全问题的相关文章

再次理解多线程线程安全问题(理解java内存模型后)

1.多线程访问的共享资源存在线程安全问题, 无外乎访问两种共享资源. 1)多线程访问方法区数据.存在线程安全问题,通过加锁 2)多线程访问实例变量:被访问对象是单例时存在线程安全,被访问对象是多例时,是线程安全的. 来说说静态变量.实例变量.局部变量在多线程下的安全问题吧! (一)验证静态变量的线程安全性: (1)从程序执行的图中我们可以看出,执行结果中有错误数据,证明了静态变量是存在资源冲突问题的. (2)程序运行结果图: 5.结论:静态变量也称为类变量,属于类对象所有,位于方法区,为所有对象

java的多线程:线程安全问题

什么是线程安全? 为什么有线程安全问题? 当多个线程同时共享,同一个全局变量或静态变量,做写的操作时,可能会发生数据冲突问题,也就是线程安全问题.但是做读操作是不会发生数据冲突问题. 抢火车的例子: 一号窗口和二号窗口同时出售火车第九九张,部分火车票会重复出售. 结论发现,多个线程共享同一个全局成员变量时,做写的操作可能会发生数据冲突问题. 二.线程安全解决办法: 问:如何解决多线程之间线程安全问题 答:使用多线程之间同步synchronized或使用锁(lock). 问:为什么使用线程同步或使

JAVA-初步认识-第十三章-多线程(线程安全问题的现象)

一. 引言 接着看,把售票的问题给说完,这里涉及到一个小问题. 在我们进行线程任务封装,并进行线程对象创建的时候,我们发现确实通过四个线程能够将一百张票卖完.但是卖票的时候,会不会出现一些小问题呢?分析整个程序给大家展示一下. 现在有四个线程,都到了run方法中来运行.大家都知道,每个线程所属的栈区当中都有自己的run方法,比如它们同时在操作堆内存中的变量,叫做num. 假设这个num已经减到了1,这是个前提. 在num=1的情况下,四个线程Thread-0,Thread-1,Thread-2,

开玩笑Web它servlet(五岁以下儿童)---- 如何解决servlet线程安全问题

servlet默认值是安全线的存在,但说白,servlet安全线实际上是一个多线程线程安全问题.因为servlet它正好是一个多线程的安全问题出现. 每次通过浏览器http同意提交请求,将一个实例servlet对象.这产生一个线程,是同一个对象.应该把该变量定义成实例变量,但这就可能发生线程不安全的问题.以下举个简单的样例: 张三看到仓库里有3件物品,他要去拿两件,但这时李四也来了.抢先他一步拿了两件物品,当张三拿的时候.仓库根本无法提供给他两件物品.这就是线程不安全. 这样的情况下应该使用sy

多线程创建方式及线程安全问题

1.创建线程方式 一:  创建线程方式一继承Thread类 public clsss MyThread extends Thread{ //重写run方法,设置线程任务 Run(){ } } main(){ new MyThread().start(); } 获取线程名称: Thread.currentThread()获取当前线程对象 Thread.currentThread().getName();获取当前线程对象的名称 二:创建线程方式-实现Runnable接口 创建线程的步骤. 1.定义类

关于CoreData和SQLite多线程访问时的线程安全问题

http://www.jianshu.com/p/95db3fc4deb3 关于CoreData和SQLite多线程访问时的线程安全问题 数据库读取操作一般都是多线程访问的.在对数据进行读取时,我们要保证其当前状态不能被修改,即读取时加锁,否则就会出现数据错误混乱.IOS中常用的两种数据持久化存储方式:CoreData和SQLite,两者都需要设置线程安全,在这里以FMDB来解释对SQLite的线程安全访问. 一:FMDB的线程安全:(以读取图片为例) 1.没有线程安全的执行方式: //****

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

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

Java---13---多线程:解决多线程的安全问题---synchronized 同步代码块

还是之前卖票的例子: class Test implements Runnable { private int num = 50; Object obj = new Object(); public void run () { while (true) { if (num >= 0) { try { Thread.sleep(20); } catch (Exception e) { // TODO: handle exception System.out.println(e.toString()

在多线程中使用静态方法是否有线程安全问题

类的成员分为两类,静态成员(static member)和实例成员(instance member).静态成员属于类,实例成员则属于对象,即类的实例. 简单讨论一下在一个类中使用静态字段(static field)和静态方法(static method)是否会有线程安全问题. 我们在知道, 静态字段(static field)和静态方法(static method)的调用是通过类来调用.静态方法不对特定的实例操作,只能访问静态成员.实例方法可对特定的实例操作,既能访问静态成员,也能访问实例成员.