精华内容
下载资源
问答
  • 多线程安全

    万次阅读 2019-01-19 15:32:57
     当个线程同时共享,同一个全局变量或静态变量,做写操作时,可能会发生数据冲突问题,也就是线程安全问题。但是做读操作时不会发生数据冲突问题。 public class ThreadDemo { public static void main...

    一.什么是线程安全

            当多个线程同时共享,同一个全局变量或静态变量,做写操作时,可能会发生数据冲突问题,也就是线程安全问题。但是做读操作时不会发生数据冲突问题。

    public class ThreadDemo {
    	
    	public static void main(String[] args) {
    		One one = new One();
    		Thread t1 = new Thread(one);
    		Thread t2 = new Thread(one);
    		t1.start();			
    		t2.start();
    	}
    }
    
    class One implements Runnable {
    	
    	private int ticketCount = 10;
    	
    	public void run() {
    		while(ticketCount > 0) {
    			System.out.println(Thread.currentThread().getName() + "出售了车票:" + ticketCount);
    			ticketCount--;
    		}
    	}
    }
    
    //控制台打印
    Thread-1出售了车票:10
    Thread-0出售了车票:10
    Thread-1出售了车票:9
    Thread-0出售了车票:8
    Thread-1出售了车票:7
    Thread-0出售了车票:6
    Thread-1出售了车票:5
    Thread-0出售了车票:4
    Thread-1出售了车票:3
    Thread-0出售了车票:2
    Thread-1出售了车票:1

    结论发现:多个线程共享同一个全局成员变量时,做写的操作可能会发生数据冲突问题。

    二.线程安全解决方案

    1.同步代码块

    synchronized(对象) {
        //可能会发生线程冲突问题
    }

    对象如同锁,持有锁的线程可以在同步中执行,没持有锁的线程即使获取cpu的执行权,也进不去。

    同步的前提

    必须要有两个或者两个以上的线程

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

    弊端:多个线程需要判断锁,较为消耗资源,抢锁的资源

    2.同步函数

    在方法上修饰synchronized称为同步函数,同步函数使用this锁

    public synchronized void sale() {
        //要执行的代码
    }

    3.静态同步函数

    方法上加入static关键字,使用synchronized关键字修饰,静态同步代码块使用的锁是,该函数所属字节码文件对象

    public synchronized static void sale() {
        //要执行的代码	
    }

    三.多线程死锁

    同步中嵌套同步,导致无法释放锁

    public class ThreadDemo {
    	
    	public static Object object1 = new Object();
    	public static Object object2 = new Object();
    	
    	public static void main(String[] args) {
    		One one = new One();
    		Thread t1 = new Thread(one);
    		t1.start();
    		
    		Two two = new Two();
    		Thread t2 = new Thread(two);
    		t2.start();
    	}
    }
    
    class One implements Runnable {
    	
    	public void run() {
    		while(true) {
    			synchronized (ThreadDemo.object1) {
    				System.out.println("oneObject1");
    				
    				synchronized (ThreadDemo.object2) {
    					System.out.println("oneObject2");
    				}
    			}
    		}
    	}
    }
    
    class Two implements Runnable {
    	
    	public void run() {
    		while(true) {
    			synchronized (ThreadDemo.object2) {
    				System.out.println("twoObject2");
    				
    				synchronized (ThreadDemo.object1) {
    					System.out.println("twoObject1");
    				}
    			}
    		}
    	}
    }
    
    //控制台打印
    oneObject2
    oneObject1
    oneObject2
    oneObject1
    oneObject2
    oneObject1
    oneObject2
    oneObject1
    twoObject2

    线程one拿了object1线程two拿了object2,都在等待对方释放锁。双方都不释放锁,产生死锁。

    四.多线程三大特性

    1.原子性:即一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行

    2.可见性:当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看到修改的值

    3.有序性:程序执行的顺序按照代码的先后顺序执行

    五.java内存模型

    java内存模型简称jmm,jmm决定一个线程对共享变量的写入时,能对一个线程可见。线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存中存储了该线程以读/写的副本。

    每个线程都有自己的本地内存,当多个线程同时访问一个数据的时候,可能本地内存没有及时刷新到主内存,所以就会发生线程安全问题。

    六.volatile关键字

    volatile关键字的作用是变量在多个线程之间可见。强制每次读取都会去主内存中取值。volatile不具备原子性。

    volatile与synchronized的区别

    1.volatile轻量级,只能修饰变量。synchronized重量级还弄修饰方法。

    2.volatile只能保证数据的可见性,不能用来同步,因为多个线程并发访问volatile修饰的变量不会阻塞。

    synchronized不仅保证可见性,而且还保证原子性,因为,只有获取了锁的线程才能进入临界区,从而保存临界区中的所有语句都全部执行,多个线程争抢synchronized锁对象时,会出现阻塞。

    线程安全性包括1.可见性  2.原子性

    volatile并不能保证线程安全性,而synchronized则可实现线程的安全性。

    七.atomiclnteger原子类

    Atomiclnteger是一个提供原子操作的integer类,通过线程安全的方式操作加减。

     

    展开全文
  • Java多线程安全问题和锁

    千次阅读 2020-02-28 17:32:26
    多线程安全问题和锁 文章目录多线程安全问题和锁线程在jvm中的特点锁的出现synchronized 关键字-监视器锁monitor lock死锁的产生和避免 什么是线程安全问题? 当多个线程同时操作同一个数据是,可能会出现数据不一样...

    多线程安全问题和锁

    什么是线程安全问题?
    当多个线程同时操作同一个数据时,可能会出现数据不一样的情况,这就是线程安全问题。
    线程安全机制用于保证多个线程访问数据时的一致性.
    线程安全问题体现在三个方面:
    1、原子性
    2、可见性
    3、有序性

    原子操作是不可分割的,体现在两个方面: 一个线程对数据的操作对于其他的线程来说是原子的,要么操作完成,要么什么也没做;当一个线程在操作数据时,不允许其他的线程参与.

    可见性是指线程对共享数据的访问是否对其他的线程可见. A线程对共享数据做了修改, B线程不一定能够立即读取到A线程修改后的数据。

    有序性包含指令重排序与内存重排序指令重排序是指CPU执行指令的顺序与程序的顺序可能不一样; 内存重排序是指内存访问顺序与感知顺序可能不一样。

    线程在jvm中的特点

    在这里插入图片描述

    1)每个线程都有独立的线程栈
    2)一个线程栈不能访问另外一个线程栈的内容
    3)所有的线程栈都可以访问堆中对象
    4)局部变星理解为存储在方法栈中,局部变量肯定不存在线程安全问题
    5)当多个线程同时访问同一个对象的实例变量,或者访问同一 个静态变量时才可能会出现线程安全问题
    6)线程安全问题不是肯定会发生的,有时可能会出现线程安全问题

    java抽象内存模型
    在这里插入图片描述
    1)每个线程都有自己独立的工作内存
    2)线程1无法访问线程2的工作内存
    3)线程在访问共享数据时,会把主内存中的共享变量复制到自己的工作内存中,线程操作的是工作内存中数据的副本

    锁的出现

    多线程并发操作同一个数据可能会引发线程安全问题。
    多个线程串行操作某个数据就不会引发线程安全问题。

    锁就是把多个线程对数据的并发操作转换为串行操作。

    想要访问共享数据,必须先获得锁对象(锁就相当于一个访问许可证)。锁对象在某一时刻只能被一个线程持有,锁具有排它性。当线程访问完共享数据后,会自动释放锁对象。

    在这里插入图片描述
    1)某个线程想要访问共享数据,必须先获得锁对象
    2)锁对象在某一时刻只能被一个线程持有当线程2获得了锁对象之后,如果还有其他线程想要访问共享数据,其他的线程也必须先获得锁对象现在锁对象被线程2持有其他的线程转为阻塞状态
    3)当线程2执行完临界区代码后,会释放锁对象阻塞队列中的线程会获得锁对象,访问共享数据
    4)注意: 多个线程想要实现同步访问,必须使用同一一个锁对象读数据时也需要进行同步,否则会出现脏读现象(另一个线程操作的中间值,还未更新)

    synchronized 关键字-监视器锁monitor lock

    synchronized的底层是使用操作系统的mutex lock实现的。

    synchronized 关键字的使用
    1、同步代码块
    1)可以定义一个常量作为锁对象
    2)只要是同一个锁对象,同步代码快可以在不同的方法体中也能同步
    2、同步实例方法
    直接使用synchronized修饰实例方法
    把整个方法体作为同步代码块,默认的锁对象就是this对象
    3、同步静态方法
    就是使用synchronized修饰静态方法
    把整个方法体作为同步代码块,默认的锁对象是 当前类的运行时类对象,简单的理解为把当前类的字节码文件作为锁

    当线程释放锁时,JMM会把该线程对应的工作内存中的共享变量刷新到主内存中
    当线程获取锁时,JMM会把该线程对应的本地内存置为无效。从而使得被监视器保护的临界区代码必须从主内 存中读取共享变量
    synchronized用的锁是存在Java对象里的

    在这里插入图片描述
    锁的是SynchronizedDemo 对象

    /*
    锁的是SynchronizedDemo 对象
     */
    public class SynchronizedDemo {
        public synchronized void methond() {
        }
    
        public static void main(String[] args) {
            SynchronizedDemo demo = new SynchronizedDemo();
            demo.methond(); // 进入方法会锁 demo 指向对象中的锁;出方法会释放 demo 指向的对象中的锁
        }
    }
    

    锁的 SynchronizedDemo 类的对象

    /*
    锁的是SynchronizedDemo 类的对象
     */
    public class SynchronizedDemo {
        public synchronized static void methond() {
        }
    
        public static void main(String[] args) {
            // 进入方法会锁 SynchronizedDemo.class 指向对象中的锁;
            // 出方法会释放 SynchronizedDemo.class 指向的对象中的锁
            methond();
        }
    }
    

    谁调用的这个方法锁的就是哪个对象

    /*
    谁调用的这个方法锁的就是哪个对象
     */
    public class SynchronizedDemo {
        public void methond() {
            // 进入代码块会锁 this 指向对象中的锁;
            // 出代码块会释放 this 指向的对象中的锁         
            synchronized (this) {
            }
        }
    
        public static void main(String[] args) {
            SynchronizedDemo demo = new SynchronizedDemo();
            demo.methond();
        }
    }
    

    死锁的产生和避免

    当多个线程需要使用多个同步锁时,如果获得锁的顺序不一致,可能会导致相互等待的情况,这种现象称为死锁。

    如何解决死锁问题?。
    如果需要获得多个锁对象时,保证获得锁对象的顺序一致,就可以避免死锁的产生。

    展开全文
  • Java 多线程安全机制

    千次阅读 2017-04-08 20:46:35
    什么是多线程安全,java中有哪些机制可以保证线程安全

    在开始讨论java多线程安全机制之前,首先从内存模型来了解一下什么是多线程的安全性。

    我们都知道java的内存模型中有主内存和线程的工作内存之分,主内存上存放的是线程共享的变量(实例字段,静态字段和构成数组的元素),线程的工作内存是线程私有的空间,存放的是线程私有的变量(方法参数与局部变量)。线程在工作的时候如果要操作主内存上的共享变量,为了获得更好的执行性能并不是直接去修改主内存而是会在线程私有的工作内存中创建一份变量的拷贝(缓存),在工作内存上对变量的拷贝修改之后再把修改的值刷回到主内存的变量中去,JVM提供了8中原子操作来完成这一过程:lock, unlock, read, load, use, assign, store, write。深入理解java虚拟机-jvm最高特性与实践这本书中有一个图很好的表示了线程,主内存和工作内存之间的关系:



    如果只有一个线程当然不会有什么问题,但是如果有多个线程同时在操作主内存中的变量,因为8种操作的非连续性和线程抢占cpu执行的机制就会带来冲突的问题,也就是多线程的安全问题。线程安全的定义就是:如果线程执行过程中不会产生共享资源的冲突就是线程安全的。


    Java里面一般用以下几种机制保证线程安全:

    1.互斥同步锁(悲观锁)

    1)Synchorized

    2)ReentrantLock

    互斥同步锁也叫做阻塞同步锁,特征是会对没有获取锁的线程进行阻塞。

    要理解互斥同步锁,首选要明白什么是互斥什么是同步。简单的说互斥就是非你即我,同步就是顺序访问。互斥同步锁就是以互斥的手段达到顺序访问的目的。操作系统提供了很多互斥机制比如信号量,互斥量,临界区资源等来控制在某一个时刻只能有一个或者一组线程访问同一个资源。

    Java里面的互斥同步锁就是Synchorized和ReentrantLock,前者是由语言级别实现的互斥同步锁,理解和写法简单但是机制笨拙,在JDK6之后性能优化大幅提升,即使在竞争激烈的情况下也能保持一个和ReentrantLock相差不多的性能,所以JDK6之后的程序选择不应该再因为性能问题而放弃synchorized。ReentrantLock是API层面的互斥同步锁,需要程序自己打开并在finally中关闭锁,和synchorized相比更加的灵活,体现在三个方面:等待可中断,公平锁以及绑定多个条件。但是如果程序猿对ReentrantLock理解不够深刻,或者忘记释放lock,那么不仅不会提升性能反而会带来额外的问题。另外synchorized是JVM实现的,可以通过监控工具来监控锁的状态,遇到异常JVM会自动释放掉锁。而ReentrantLock必须由程序主动的释放锁。

    互斥同步锁都是可重入锁,好处是可以保证不会死锁。但是因为涉及到核心态和用户态的切换,因此比较消耗性能。JVM开发团队在JDK5-JDK6升级过程中采用了很多锁优化机制来优化同步无竞争情况下锁的性能。比如:自旋锁和适应性自旋锁,轻量级锁,偏向锁,锁粗化和锁消除。



    2.非阻塞同步锁

    1) 原子类(CAS)

    非阻塞同步锁也叫乐观锁,相比悲观锁来说,它会先进行资源在工作内存中的更新,然后根据与主存中旧值的对比来确定在此期间是否有其他线程对共享资源进行了更新,如果旧值与期望值相同,就认为没有更新,可以把新值写回内存,否则就一直重试直到成功。它的实现方式依赖于处理器的机器指令:CAS(Compare And Swap)

    JUC中提供了几个Automic类以及每个类上的原子操作就是乐观锁机制。

    不激烈情况下,性能比synchronized略逊,而激烈的时候,也能维持常态。激烈的时候,Atomic的性能会优于ReentrantLock一倍左右。但是其有一个缺点,就是只能同步一个值,一段代码中只能出现一个Atomic的变量,多于一个同步无效。因为他不能在多个Atomic之间同步。 

    非阻塞锁是不可重入的,否则会造成死锁。

    3.无同步方案

    1)可重入代码

    在执行的任何时刻都可以中断-重入执行而不会产生冲突。特点就是不会依赖堆上的共享资源

    2)ThreadLocal/Volaitile

    线程本地的变量,每个线程获取一份共享变量的拷贝,单独进行处理。

    3)  线程本地存储

    如果一个共享资源一定要被多线程共享,可以尽量让一个线程完成所有的处理操作,比如生产者消费者模式中,一般会让一个消费者完成对队列上资源的消费。典型的应用是基于请求-应答模式的web服务器的设计

    展开全文
  • Java Tread多线程(2)多线程安全问题

    千次阅读 2014-09-17 22:40:36
    本文演示,Tread多线程安全问题,以及几种解决多线程安全方式。 1)一个线程不安全的Demo 2)线程同步(synchronized,函数同步,this锁,Class对象锁) 一、小Demo演示引出线程安全问题: 二、线程同步 问题:对于...

    本文演示,Tread多线程安全问题,以及几种解决多线程安全方式(线程同步)。

    1)一个线程不安全的Demo

    2)线程同步(synchronized,函数同步,this锁,Class对象锁)


    一、小Demo演示引出线程安全问题:

    package thread.runable1.qdj;
    //1.定义类实现Runnable接口
    class RunDemo1 implements Runnable
    {
    	private int x = 5;
    	//2.覆盖Runnable接口中的run方法
    	//将线程代码存放在run中
    	public void run() 
    	{
    		while (true)
    		{
    			if (x > 0)
    			{
    				//添加sleep(),注意:sleep()会抛出异常
    				try {
    					Thread.sleep(10);  //让线程睡眠10ms
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    				System.out.println("Runnable:"+x);
    				--x;
    			}
    		}
    	}
    }
    public class CRunableDemo1 {
    
    	public static void main(String[] args) {
    		RunDemo1 r = new RunDemo1();
    		//3.通过Thread类建立线程对象,并将Runnable接口的子类对象作为参数
    		Thread t1 = new Thread(r);
    		Thread t2 = new Thread(r);
    		Thread t3 = new Thread(r);
    		Thread t4 = new Thread(r);
    		//4.使用start开启线程
    		t1.start();
    		t2.start();
    		t3.start();
    		t4.start();
    	}
    }

    运行显示结果:


    以上打印出了0,-1,-2等数字,发现没?(线程出问题了吧!!!)
    问题:出问题的原因是什么呢?

    解释:线程1进入,强制睡眠10ms;此时线程2进入,又强制睡眠10ms;线程3进入又强制睡眠10ms;线程4进入再强制睡眠10ms;

    注意,以上4个线程睡眠时都已经进入了if语句,进入的时候x>0还是成立的;

    好了,线程1醒来,开始打印打印5,4,3,2,这时候--x还没执行,线程2就醒来了,抢去了cpu的执行权.....................


    二、线程同步

    问题:对于上面的问题,我们是不是可以采取一个这样的措施?当线程1执行run代码段的时候,我们不让其他的线程来执行,直到线程1执行完,其他的线程才可以进入。

    解决方案:好在Java里面本来就有这样的函数,将代码段包裹起来,就可以达到上面问题描述的效果。函数名:synchronized,需要一个参数,随便传个对象就ok了(具体参数区别分析,请往下拉见附录1)。

    1)一个简单的解决方案:

    package thread.runable1.qdj;
    //1.定义类实现Runnable接口
    class RunDemo1 implements Runnable
    {
    	private int x = 5;
    	Object obj = new Object();
    	//2.覆盖Runnable接口中的run方法
    	//将线程代码存放在run中
    	public void run() 
    	{
    		while (true)
    		{
    			synchronized (obj) 
    			{
    				if (x > 0)
    				{
    					//添加sleep(),注意:sleep()会抛出异常
    					try {
    						Thread.sleep(10);  //让线程睡眠10ms
    					} catch (Exception e) {
    						e.printStackTrace();
    					}
    					System.out.println("Runnable:"+x);
    					--x;
    				}
    			}
    		}
    	}
    }
    public class CRunableDemo1 {
    
    	public static void main(String[] args) {
    		RunDemo1 r = new RunDemo1();
    		//3.通过Thread类建立线程对象,并将Runnable接口的子类对象作为参数
    		Thread t1 = new Thread(r);
    		Thread t2 = new Thread(r);
    		Thread t3 = new Thread(r);
    		Thread t4 = new Thread(r);
    		//4.使用start开启线程
    		t1.start();
    		t2.start();
    		t3.start();
    		t4.start();
    	}
    }
    
    运行结果显示:


    2)换一种更简单的解决方法:函数同步(将synchronized直接添加在函数前面)

    说明:有没有发现,函数就是对多个语句的打包?但是,函数只是打包,而没有像上面的synchronized一样实现同步。但是有一种方法可以达到这个效果,看下面的小Demo就明白了。

    package thread.runable1.qdj;
    //同步函数
    class SynFunc 
    {
    	private int x = 5;
    	public synchronized void aFunc()
    	{
    		while (true)
    		{
    			if (x > 0)
    			{
    				//添加sleep(),注意:sleep()会抛出异常
    				try {
    					Thread.sleep(10);  //让线程睡眠10ms
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    				System.out.println("Runnable:"+x);
    				--x;
    			}
    		}
    	}
    }
    //1.定义类实现Runnable接口
    class RunDemo1 implements Runnable
    {
    	private SynFunc syn = new SynFunc();
    	//2.覆盖Runnable接口中的run方法
    	//将线程代码存放在run中
    	public void run() 
    	{
    		syn.aFunc();
    	}
    }
    public class CRunableDemo1 {
    
    	public static void main(String[] args) {
    		RunDemo1 r = new RunDemo1();
    		//3.通过Thread类建立线程对象,并将Runnable接口的子类对象作为参数
    		Thread t1 = new Thread(r);
    		Thread t2 = new Thread(r);
    		Thread t3 = new Thread(r);
    		Thread t4 = new Thread(r);
    		//4.使用start开启线程
    		t1.start();
    		t2.start();
    		t3.start();
    		t4.start();
    	}
    }
    
    运行结果显示:(同上)


    附录1:对于函数锁中synchronized中的参数的解释分析(我们先看一下下面这个小Demo)

    package thread.runable1.qdj;
    
    //1.定义类实现Runnable接口
    class RunDemo1 implements Runnable
    {
    	private int x = 100;
    	Object obj = new Object();
    	boolean flag = true;
    	//2.覆盖Runnable接口中的run方法
    	//将线程代码存放在run中
    	public void run() 
    	{
    		if (flag)
    		{
    			while (true)
    			{
    				synchronized(obj)
    				{
    					if (x > 0)
    					{
    						//添加sleep(),注意:sleep()会抛出异常
    						try {
    							Thread.sleep(10);  //让线程睡眠10ms
    						} catch (Exception e) {
    							e.printStackTrace();
    						}
    						System.out.println("Runnable:"+x);
    						--x;
    					}
    				}
    			}
    		}
    		else 
    		{
    			while (true)
    				aFunc();
    		}
    	}
    	public synchronized void aFunc()
    	{
    		while (true)
    		{
    			if (x > 0)
    			{
    				//添加sleep(),注意:sleep()会抛出异常
    				try {
    					Thread.sleep(10);  //让线程睡眠10ms
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    				System.out.println("Runnable:"+x);
    				--x;
    			}
    		}
    	}
    }
    public class CRunableDemo1 {
    
    	public static void main(String[] args) {
    		RunDemo1 r = new RunDemo1();
    		//3.通过Thread类建立线程对象,并将Runnable接口的子类对象作为参数
    		Thread t1 = new Thread(r);
    		Thread t2 = new Thread(r);
    		//4.使用start开启线程
    		t1.start();
    		//添加sleep(),注意:sleep()会抛出异常
    		try {
    			Thread.sleep(10);  //让线程睡眠10ms
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		r.flag = false;
    		t2.start();
    	}
    }
    
    运行显示结果:



    郁闷吧,又出现线程安全问题了,可是我们分明都加了锁的呀?这是什么原因导致的呢?其实,问题就出在了,synchronized里面的参数上。

    函数同步锁定的是this,而上面的小Demo里面,一个是函数同步锁(this),另外一个是obj锁,发现没?解决方案:将obj锁改为this锁就没问题了。

    解决后的小Demo:

    package thread.runable1.qdj;
    
    //1.定义类实现Runnable接口
    class RunDemo1 implements Runnable
    {
    	private int x = 100;
    	Object obj = new Object();
    	boolean flag = true;
    	//2.覆盖Runnable接口中的run方法
    	//将线程代码存放在run中
    	public void run() 
    	{
    		if (flag)
    		{
    			while (true)
    			{
    				synchronized(this)
    				{
    					if (x > 0)
    					{
    						//添加sleep(),注意:sleep()会抛出异常
    						try {
    							Thread.sleep(10);  //让线程睡眠10ms
    						} catch (Exception e) {
    							e.printStackTrace();
    						}
    						System.out.println("Runnable:"+x);
    						--x;
    					}
    				}
    			}
    		}
    		else 
    		{
    			while (true)
    				aFunc();
    		}
    	}
    	public synchronized void aFunc()
    	{
    		while (true)
    		{
    			if (x > 0)
    			{
    				//添加sleep(),注意:sleep()会抛出异常
    				try {
    					Thread.sleep(10);  //让线程睡眠10ms
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    				System.out.println("Runnable:"+x);
    				--x;
    			}
    		}
    	}
    }
    public class CRunableDemo1 {
    
    	public static void main(String[] args) {
    		RunDemo1 r = new RunDemo1();
    		//3.通过Thread类建立线程对象,并将Runnable接口的子类对象作为参数
    		Thread t1 = new Thread(r);
    		Thread t2 = new Thread(r);
    		//4.使用start开启线程
    		t1.start();
    		//添加sleep(),注意:sleep()会抛出异常
    		try {
    			Thread.sleep(10);  //让线程睡眠10ms
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		r.flag = false;
    		t2.start();
    	}
    }
    
    运行显示结果:



    附录2:提出另外一个问题,既然函数同步锁定的是this,那么如下的这个函数要如何解释?静态函数没有this,如何锁定?

    public static synchronized void aFunc()
    	{
    		while (true)
    		{
    			if (x > 0)
    			{
    				//添加sleep(),注意:sleep()会抛出异常
    				try {
    					Thread.sleep(10);  //让线程睡眠10ms
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    				System.out.println("Runnable:"+x);
    				--x;
    			}
    		}
    	}
    解决方案:静态函数,是类函数由类调用。其实这里static函数的锁是Class对象。下面注意看如下小Demo中synchronized的参数。

    解决后的小Demo:

    package thread.runable1.qdj;
    
    //1.定义类实现Runnable接口
    class RunDemo1 implements Runnable
    {
    	private static int x = 100;
    	boolean flag = true;
    	//2.覆盖Runnable接口中的run方法
    	//将线程代码存放在run中
    	public void run() 
    	{
    		if (flag)
    		{
    			while (true)
    			{
    				synchronized(RunDemo1.class)
    				{
    					if (x > 0)
    					{
    						//添加sleep(),注意:sleep()会抛出异常
    						try {
    							Thread.sleep(10);  //让线程睡眠10ms
    						} catch (Exception e) {
    							e.printStackTrace();
    						}
    						System.out.println("Runnable:"+x);
    						--x;
    					}
    				}
    			}
    		}
    		else 
    		{
    			while (true)
    				aFunc();
    		}
    	}
    	public static synchronized void aFunc()
    	{
    		while (true)
    		{
    			if (x > 0)
    			{
    				//添加sleep(),注意:sleep()会抛出异常
    				try {
    					Thread.sleep(10);  //让线程睡眠10ms
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    				System.out.println("Runnable:"+x);
    				--x;
    			}
    		}
    	}
    }
    public class CRunableDemo1 {
    
    	public static void main(String[] args) {
    		RunDemo1 r = new RunDemo1();
    		//3.通过Thread类建立线程对象,并将Runnable接口的子类对象作为参数
    		Thread t1 = new Thread(r);
    		Thread t2 = new Thread(r);
    		//4.使用start开启线程
    		t1.start();
    		//添加sleep(),注意:sleep()会抛出异常
    		try {
    			Thread.sleep(10);  //让线程睡眠10ms
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		r.flag = false;
    		t2.start();
    	}
    }
    

    运行显示结果:(同上)



    展开全文
  • iOS 多线程安全数组

    千次阅读 2017-03-15 17:14:53
    iOS-SDK只提供了非线程安全的数组。如果要多线程并发的使用一个数组对象就必须要加锁。在多线程下使数组安全,就是通过给数组的访问和修改添加同步限制,使数组多线程安全
  • 多线程安全计数器

    千次阅读 2016-05-06 22:36:20
    在做性能测试时,需要统计运行一段时间内库使用锁的次数、获取时间戳的次数...可以使用下面的多线程安全的计数器 /// Counter.h #ifndef __COUNTER_H__ #define __COUNTER_H__ #include "Mutex.h" class CCounter {
  • 多线程安全问题

    千次阅读 2018-12-05 14:52:31
    问:如何解决多线程之间线程安全问题? 答:使用多线程之间同步synchronized或使用锁(lock)。 问:为什么使用线程同步或使用锁能解决线程安全问题呢? 答:将可能会发生数据冲突问题(线程不安全问题...
  • msyql的多线程安全问题

    千次阅读 2018-06-05 11:54:54
    mysql的多线程安全问题:在mysql_real_connect时出现 段错误 mysql的多线程安全问题:在mysql_real_connect时出现段错误。问题简化重现19 #include20 #include 2122 void* func(void* arg)23 {24 MYSQL* mysql = ...
  • C#多线程控制进度条之多线程安全

    千次阅读 2010-03-25 10:51:00
    C#多线程控制进度条之多线程安全的具体内容是什么呢?让我们开始吧:到这里为止,我们已经解决了长任务的难题和传递参数的困扰。但是我们真的解决了全部问题吗?回答是否定的。C#多线程控制进度条之多线程安全的问题...
  • 实例探索多线程安全问题1.利用继承Thread类的方式卖电影票2.实现Runnable接口的方式卖电影票3.线程安全问题的实例发生 临近春节,各大电影院都在筹备准备上映贺岁大片。假设某家电影院持有唐探3的票100张,而且它...
  • lettuce底层通过netty实现了多线程安全,即一个tcp连接可以同时处理多个redis操作, 我现在比较疑问的是,lettuce怎么保证返回的结果能够对应各自发送的redis操作。 ``` @Test public void testLettuce() ...
  • 浅析libcurl多线程安全问题

    万次阅读 2016-07-09 13:08:28
    浅析libcurl多线程安全问题 背景:使用多线程libcurl发送请求,在未设置超时或长超时的情况下程序运行良好。但只要设置了较短超时(小于180s),程序就会出现随机的coredump。并且栈里面找不到任何有用的信息。 ...
  • 项目中开发用到ArrayList时,产生一些问题。 记录一些自己的理解,当然网上了有其它的源码分析的资料1、单线程下...即多线程安全结论:1、单线程下ArrayList获取跌代器iterator后,是不能再修改ArrayList的长度的,...
  • LinkedBlockingQueue多线程安全的保障
  • c和c++调用Python 多线程安全

    千次阅读 2018-01-18 09:49:34
    一、C++调用Python API多线程安全参考网页:http://blog.csdn.net/cedricporter/article/details/6810665Python不支持多线程,如果在c使用多线程就会报错使用GIL可以解决。主要函数1.PyGILState_STATE PyGILState_...
  • 上一篇博客《synchronized 的用法》中讲解了synchronized 关键字的 所有具体用法, 以及它是如何解决多线程安全问题的。 借这篇文章回顾一下线程通信的基础知识,可能这些知识点大家都能略知一二,但实际项目开发中 ...
  • 多线程安全问题的解决方案: 首先我们得明白两个概念:同步 和 互斥; 同步——这是线程 or 进程之间的 合作关系。对多个线程在执行次序上进行协调,以使并发的各个线程能更好的利共享资源,相互合作。多个线程...
  • iOS 多线程安全 与 可变字典

    千次阅读 2019-07-03 07:15:15
    这周最大的收获是稍稍通透了 多线程安全字典的重要性。 诱因是,发现了有字典坏地址错误 果断以为是 value 或者 key 是可能出现了空值,补充了潜在的判断,虽然有的位置已经预判断的,但是真正赋值的时候并...
  • Java多线程安全问题及解决方案

    千次阅读 2016-03-16 22:17:48
    Java多线程安全问题及解决方案 一、问题引入 通过最常见的多窗口售票问题引入线程安全的问题。代码如下: 注:这里使用Runnable接口来实现线程,这样做是为了共享代售票这个资源,如果我们使用继承Thread来操作,...
  • C++多线程安全类的问题

    千次阅读 2015-02-28 18:22:59
    我们是多么渴望各种C++类都是多线程安全的,然而一旦涉及到对象间的交互,这样的渴望可能就只能是奢望了。下面,我们以设计一个双向链结点为例,看看要使其多线程安全将会带来一些什么问题。 class ...
  • springboot如何保证多线程安全

    千次阅读 2020-03-18 15:33:42
    我们在@RestController下,一般都是@AutoWired一些Service,由于这些Service都是单例,对于在Controller中调用他们的方法,由于方法在JVM中属于栈操作,对于每一个线程来说,栈都是独立的,所以是线程安全的。...
  • 多线程安全——起源 数据的实效性问题(数据时效过期):我们知道即使多个线程在同一个进程内可以共享内存数据,但内存共分为工作内存和主内存;工作内存就是,线程的在cpu三级缓存中的内存数据;主内存,就是内存...
  • 针对面试题中频频出现的问题:写一个多线程安全的单例模式。在此做一个记录。 很多博客列举了多种线程安全单利模式的例子,写的很棒,推荐给大家看:https://www.cnblogs.com/jiuyi/p/6105037.html 我这里只提供...
  • 用于解决多线程安全问题的方式: 1. 同步代码块 (隐式锁) 2. 同步方法(隐式锁) 3. 同步锁 Lock( jdk 1.5 后)  注意:是一个显示锁,需要通过 lock() 方法上锁,必须通过 unlock() 方法进行释放锁 下面举一个售票...
  • CoreData多线程安全

    万次阅读 2013-07-16 16:59:10
    CoreData中的NSManagedObjectContext在多线程中不安全,如果想要多线程访问CoreData的话,最好的方法是一个线程一个NSManagedObjectContext, ,每个NSManagedObjectContext对象实例都可以使用同一个...
  • C# Dictionary多线程安全访问问题

    千次阅读 2018-06-01 17:12:49
    Dictionary是非线程安全的类型,操作的时候需要对其进行线程安全处理,最简单的方式就是加锁(lock)。数据变量:private static Dictionary<string, VirtualVideoChannel> m_list_video_channel_all = ...
  • 用买票例子讲讲多线程安全问题

    千次阅读 2014-08-31 23:35:25
    在javase中多线程安全问题,买票的例子几乎是都会讲到,今天
  • 关于多线程安全的解决方案

    千次阅读 2012-05-10 10:07:22
    在spring中默认的service是singleton的,这就造成了一个问题:在有共享变量(比如static变量,有时候我们不得不这么做)的时候,需要考虑到该共享变量的多线程安全问题。  解决这个问题有几个方法:  1.借助...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 58,804
精华内容 23,521
关键字:

多线程安全