线程安全

1.定义

多线程访问共享数据,会产生线程安全问题。

2.代码模拟

卖票Ticked类:

package com.lanyue.day22;

public class Person {

    public static void main(String[] args) {

        Car one = new Car("宝马");

        one.start();

        Driver two = new Driver();
new Thread(two).start(); new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0;i < 5;i++){ try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第二个司机第" + i + "次报数中。");
}
}
}).start();
}
}

卖票窗口Window类

package com.lanyue.day23;

public class Windows {

    public static void main(String[] args) {

        Ticked runnable = new Ticked();
Thread one = new Thread(runnable);
Thread two = new Thread(runnable);
Thread three = new Thread(runnable); one.start();
two.start();
three.start();
}
}

程序执行图

3.解决方法

当使用多个线程对同一个资源有写操作时,就容易出现线程安全问题。为解决这个问题,Java提供了同步机制synchronized来解决这个问题。

那么如何实现所谓的同步机制呢?有三个方法:

1.同步代码块

synchronized用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。

示例:

synchronized (同步锁){
//代码块.

注意:

(1)同步代码块中的锁对象可以是任意对象。

(2)必须保证多个线程使用的锁对象是同一个对象。

示例代码:

package com.lanyue.day23;

public class Ticked implements Runnable {

    public Integer ticks = 100;
public Object obj = new Object();
public boolean state = true; @Override
public void run() { while(state){ synchronized (obj){ if(ticks-- > 0){ System.out.println(Thread.currentThread().getName() + "窗口卖出了第" + (100 - ticks) + "张票"); }else{ state = false;
}
}
}
}
}

2.同步方法

(1)普通同步锁方法:

只需要在方法前加一个修饰符 synchronized 即可(本质上也是利用锁对象锁定的,这个锁是this)。

格式:

权限修饰符 synchronized 返回值类型 方法名(参数){

方//法体

示例代码:

package com.lanyue.day23;

public class TickedTwo implements Runnable{

    public Integer ticks = 100;
public boolean state = true; @Override
public void run(){ while(state){ view();
}
} public synchronized void view(){ if(ticks-- > 0){ System.out.println(Thread.currentThread().getName() + "窗口卖出了第" + (100 - ticks) + "张票"); }else{ state = false;
}
}
}

(3)静态同步方法

本质也是利用锁对象,这个锁对象是class文件对象

格式:

权限修饰符 static synchronized 返回值类型 方法名(参数){

//方法体。

示例代码:

package com.lanyue.day23;

public class TickedThree implements Runnable{

    public static Integer ticks = 100;
public static boolean state = true; @Override
public void run() { while(state){ view();
}
} public static synchronized void view(){ if(ticks-- > 0){ System.out.println(Thread.currentThread().getName() + "窗口卖出了第" + (100 - ticks) + "张票"); }else{ state = false;
}
}
}

3.锁机制

Lock接口

ReentrantLock类是Lock接口的实现类。

使用步骤:

(1)在成员变量位置创建 ReentrantLock 对象。

(2)在可能发生线程安全问题的代码前调用ReentrantLock 对象的lock()方法锁住共享数据。

(3)在可能发生线程安全问题的代码后调用ReentrantLock  对象的unlock()方法解锁共享资源。

代码示例:

package com.lanyue.day23;

import java.util.concurrent.locks.ReentrantLock;

public class TickedFour implements Runnable {

    public ReentrantLock myLock = new ReentrantLock();
public Integer ticks = 100;
public boolean state = true; @Override
public void run() { while(state){ myLock.lock();
if(ticks-- > 0){ System.out.println(Thread.currentThread().getName() + "窗口卖出了第" + (100 - ticks) + "张票"); }else{ state = false;
} myLock.unlock();
}
}
}

Java第二十四天,线程安全的更多相关文章

  1. “全栈2019”Java第二十四章:流程控制语句中决策语句switch下篇

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  2. 学JAVA第二十四天,Set集合与StringBuilder

    下面的内容需要慢慢看,因为,我的语言表达能力不是很好 首先说Set把,Set集合是一个无序且不允许重复的集合,而且查找效率也是快的可怕的. 但是,有些时候,我们必须要用储存多个相同的值时,Set也是可 ...

  3. “全栈2019”Java多线程第二十四章:等待唤醒机制详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  4. javaSE第二十四天

    第二十四天    363 1:多线程(理解)    363 (1)JDK5以后的Lock锁    363 A:定义    363 B:方法:    364 C:具体应用(以售票程序为例)    364 ...

  5. Gradle 1.12用户指南翻译——第二十四章. Groovy 插件

    其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://g ...

  6. Java 1.ExecutorService四种线程池的例子与说明

    1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable() { @Override public void run() { ...

  7. NeHe OpenGL教程 第二十四课:扩展

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  8. Python第二十四天 binascii模块

    Python第二十四天 binascii模块 binascii用来进行进制和字符串之间的转换 import binascii s = 'abcde' h = binascii.b2a_hex(s) # ...

  9. SQL注入之Sqli-labs系列第二十四关(二阶注入)

    开始挑战第二十四关(Second Degree Injections) 0x1 前言 SQL注入一般分为两类:一阶SQL注入(普通SQL注入),二阶SQL注入 .二次注入不是注入两次的意思,请不要混淆 ...

随机推荐

  1. 一键配置openstack-cata版的在线yum源

    下面脚本可以直接复制来配置openstack-ocata版的yum源: echo "nameserver 8.8.8.8 nameserver 119.29.29.29 nameserver ...

  2. NIO中的ZeroCopy

    前文提到网络IO可以使用多路复用技术,而文件IO无法使用多路复用,但是文件IO可以通过减少底层数据拷贝的次数来提升性能,而这个减少底层数据拷贝次数的技术,就叫做ZeroCopy. 操作系统层面的Zer ...

  3. SpringMVC框架——常用注解

    @RequestMapping Spring MVC 通过 @RequestMapping 注解将请求与业务方法进行映射,在方法定义处,在类定义都可以添加该注解. 常用参数: 1.value:指定请求 ...

  4. MySQL笔记(7)-- 事务和实现

    一.背景 前面有说到InnoDB是事务型引擎,那什么是事务?事务的特性是什么?它所对应的隔离级别是哪些?是怎么实现的?下面来详细讨论下. 二.事务的理解 事务就是一组原子性的SQL查询,或者说一个独立 ...

  5. adt-bundle环境搭建(Win7+Win10)

    一.adt-bundle安装包 安装包的下载地址:http://tools.android-studio.org/index.php/adt-bundle-plugin  链接中包含有windows. ...

  6. Java——Collection集合

    ##Collection集合 1.Collection集合是单列集合 2.Collection是所有单列集合最顶层的接口,定义了所有单列集合的共性方法 任意的单列集合都可以使用Collection接口 ...

  7. wr720n v4 折腾笔记(二):刷入不死Uboot

    0x01 前言 接着上节刷入Openwrt开始说起,此次开始刷入不死Uboot,刷入之后就可以在Uboot里面随便刷机,再也不怕成砖了. 固件附件地址: 下载地址1(还是之前一的包) flash文件地 ...

  8. 【笔记3-31】Python语言基础-序列sequence

    序列sequence 可变序列 列表 list 字典 不可变序列 字符串 str 元祖 tuple 通过索引修改列表 del 删除元素 del my_list[2] 切片赋值只能是序列 .insert ...

  9. IO多路复用(IO Multiplexing)

    什么是IO多路复用 为什么要有IO多路复用 作者总结 遵循学习新知识的三部曲:是什么?为什么?怎么用? 作者前言:IO多路复用本质上是网络通信过程中的一个技术名词. 什么是IO多路复用 一个用机场管理 ...

  10. AI的博弈论,一份插图教程

    介绍 我想先问一个简单的问题--你能认出下图中的两个人吗? 我肯定你说对了.对于我们这些早期数学发烧友来说,电影<美丽心灵>(A Beautiful Mind)已经深深地印在了我们的记忆中 ...