竞争条件

1.竞争条件:

在java多线程中,当两个或以上的线程对同一个数据进行操作的时候,可能会产生“竞争条件”的现象。这种现象产生的根本原因是因为多个线程在对同一个数据进行操作,此时对该数据的操作是非“原子化”的,可能前一个线程对数据的操作还没有结束,后一个线程又开始对同样的数据开始进行操作,这就可能会造成数据结果的变化未知。

package com.huojg.test;

public class TestThread {  

    public static void main(String[] args) {
// new 出一个新的对象 t
MyThread t = new MyThread();
/**
* 两个线程是在对同一个对象进行操作
*/
Thread ta = new Thread(t, "Thread-A");
Thread tb = new Thread(t, "Thread-B");
ta.start();
tb.start();
}
} class MyThread implements Runnable {
// 变量 a 被两个线程共同操作,可能会造成线程竞争
int a = 10;
@Override
public void run() {
for (int i = 0; i < 5; i++) {
a -= 1;
try {
Thread.sleep(1);
} catch (InterruptedException e) {}
System.out.println(Thread.currentThread().getName() + " → a = " + a);
}
}
}

结果显示:

Thread-A → a = 8
Thread-B → a = 8
Thread-A → a = 6
Thread-B → a = 6
Thread-B → a = 4
Thread-A → a = 4
Thread-B → a = 2
Thread-A → a = 2
Thread-A → a = 0
Thread-B → a = 0

从上面的结果中我们可以看到,在线程A对数据进行了操作之后,他还没有来得及数据进行下一次的操作,此时线程B也对数据进行了操作,导致数据a一次性被减了两次,以至于a为9的时候的值根本没有打印出来,a为0的时候却被打印了两次。

那么,我们要如何才能避免结果这种情况的出现呢?

2.线程锁

如果在一个线程对数据进行操作的时候,禁止另外一个线程操作此数据,那么,就能很好的解决以上的问题了。这种操作叫做给线程加锁。

package com.huojg.test;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* 在Java多线程中,当两个或以上的线程对同一个数据进行操作的时候,可能会产生“竞争条件”的现象。这种现象产生的根本原因是因为多个线程在对同一个数据进行操作,此时对该数据的操作是非“原子化”的,
* 可能前一个线程对数据的操作还没有结束,后一个线程又开始对同样的数据开始进行操作,这就可能会造成数据结果的变化未知。
*
*
* 2.线程锁 如果在一个线程对数据进行操作的时候,禁止另外一个线程操作此数据,那么,就能很好的解决以上的问题了。这种操作叫做给线程加锁。
* */
public class TestThread { public static void main(String[] args) {
// new 出一个新的对象 t
MyThread t = new MyThread();
/**
* 两个线程是在对同一个对象进行操作
*/
Thread ta = new Thread(t, "Thread-A");
Thread tb = new Thread(t, "Thread-B");
ta.start();
tb.start();
}
} class MyThread implements Runnable {
// 声明锁
private Lock lock = new ReentrantLock();
// 变量 a 被两个线程共同操作,可能会造成线程竞争
int a = 10;
@Override
public void run() {
// 加锁
lock.lock();
for (int i = 0; i < 5; i++) {
a -= 1;
try {
Thread.sleep(1);
} catch (InterruptedException e) {}
System.out.println(Thread.currentThread().getName() + " → a = " + a);
}
lock.unlock();
}
}

运行结果:

Thread-A → a = 9
Thread-A → a = 8
Thread-A → a = 7
Thread-A → a = 6
Thread-A → a = 5
Thread-B → a = 4
Thread-B → a = 3
Thread-B → a = 2
Thread-B → a = 1
Thread-B → a = 0

上面的代码给出了给线程枷锁的方式,可以看到,在线程对数据进行操作之前先给此操作加一把锁,那么在此线程对数据进行操作的时候,其他的线程无法对此数据进行操作,只能“阻塞”在一边等待当前线程对数据操作结束后再对数据进行下一次的操作,当前线程在数据的操作完成之后会解开当前的锁以便下一个线程操作此数据

用synchronized关键字加锁来对方法进行加锁:结果一样;

总结:

Java中的多线程,当多个线程对一个数据进行操作时,可能会产生“竞争条件”的现象,这时候需要对线程的操作进行加锁,来解决多线程操作一个数据时可能产生问题。加锁方式有两种,一个是申明Lock对象来对语句快进行加锁,另一种是通过synchronized 关键字来对方法进行加锁。以上两种方法都可以有效解决Java多线程中存在的竞争条件的问题。

Java多线程中的竞争条件、锁以及同步的概念的更多相关文章

  1. java多线程中并发集合和同步集合有哪些?区别是什么?

    java多线程中并发集合和同步集合有哪些? hashmap 是非同步的,故在多线程中是线程不安全的,不过也可以使用 同步类来进行包装: 包装类Collections.synchronizedMap() ...

  2. Java多线程中的常用方法

    本文将带你讲诉Java多线程中的常用方法   Java多线程中的常用方法有如下几个 start,run,sleep,wait,notify,notifyAll,join,isAlive,current ...

  3. Java多线程中的死锁

    Java多线程中的死锁 死锁产生的原因 线程死锁是指由两个以上的线程互相持有对方所需要的资源,导致线程处于等待状态,无法往前执行. 当线程进入对象的synchronized代码块时,便占有了资源,直到 ...

  4. java多线程中的三种特性

    java多线程中的三种特性 原子性(Atomicity) 原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行. 如果一个操作时原子性的,那么多线程并 ...

  5. java 多线程中的wait方法的详解

    java多线程中的实现方式存在两种: 方式一:使用继承方式 例如: PersonTest extends Thread{ String name; public PersonTest(String n ...

  6. java多线程中最佳的实践方案是什么?

    java多线程中最佳的实践方案是什么? 给你的线程起个有意义的名字.这样可以方便找bug或追踪.OrderProcessor, QuoteProcessor or TradeProcessor 这种名 ...

  7. java 多线程中的锁的类别及使用

    目前在Java中存在两种锁机制: synchronized Lock Lock接口及其实现类是JDK5增加的内容,其作者是大名鼎鼎的并发专家Doug Lea. 数据同步需要依赖锁,那锁的同步又依赖谁? ...

  8. java多线程中的死锁、活锁、饥饿、无锁都是什么鬼?

    死锁.活锁.饥饿是关于多线程是否活跃出现的运行阻塞障碍问题,如果线程出现了这三种情况,即线程不再活跃,不能再正常地执行下去了. 死锁 死锁是多线程中最差的一种情况,多个线程相互占用对方的资源的锁,而又 ...

  9. java多线程系类:JUC锁:01之框架

    本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下:01. Java多线程系列--"JUC锁"01之 框架02. Java多线程系列--"JUC锁&q ...

随机推荐

  1. eclipse无法导入Android工程的解决办法

    我以前在windows平台下写的android源代码无法通过import"existing project into workspace"导入到mac的eclipse中,直接搜不见 ...

  2. RTU模式与ASCII模式有什么不同

    所有设备必须必须实现 RTU 模式.ASCII 传输模式是选项,即默认设置必须为 RTU 模式. 当设备使用RTU (Remote Terminal Unit) 模式在 Modbus 串行链路通信, ...

  3. Creating and Flashing UBIFS with MTD Utils

    转:http://wiki.atlas-embedded.com/index.php?title=Creating_and_Flashing_UBIFS_with_MTD_Utils Contents ...

  4. Assembly.Load动态加载程序集而不占用文件 z

    方式一:占用文件的加载 Assembly assembly = Assembly.Load(path); 用上面的方法可以动态的加载到dll,但是用这种方法加载到的dll一直到程序运行结束都是占用的d ...

  5. VBA Collection用法总结

    Sub test() ' Dim s As Collection '定义s变量为集合对象 ' Set s = New Collection '初始化集合对象s (否则无法使用) Dim s As Ne ...

  6. 基本数据类型,包装类型,String类型数据之间的转换

    java中所有的类都从java.lang.Object类派生而来,在java语言中,除基本数据类型以外,基本数据类型有java类库体统了包装类:Integer类保存整形变量,Boolean类保存布尔变 ...

  7. 为什么我不使用Kubernetes的Ingress

    为什么我不使用Kubernetes的Ingress 很不幸,据我所知Kubernetes的文档不是很完美,这就是为什么有很多同学在使用它的时候会遇到很多的坑,Ingress这个组件就是这些坑中的一个. ...

  8. PHP模板解析入门

    学习:李炎恢PHP视频第二季 模板引擎的特点: 1.鼓励分离:让更个系统的可读性和维护性得到提高. 2.促进分工:使得程序员和美工去专心处理自己的设计. 3.比PHP更容易解析:编译文件和缓存文件加载 ...

  9. 关于使用ueditor时候遇到的情况

    在使用百度ueditor的时候遇到的一下情况 1.点击图片之后图片无法在编辑器内显示 2.从数据库取出图片的时候无法在编辑器内显示 3.内容存放入数据库取出来之后,HTML效果不显示 流程: 1.引入 ...

  10. GTK+重拾--09 GTK+中的组件(一)

    (一):写在前面 在这篇文章中主要介绍了GTK+程序中的各种构件,这是解说构件的第一个部分,另外一部分将在下一个小节中讲到. 构件是建立一个GUI程序的基础.在GTK+的长期发展过程中.一些特定的构件 ...