线程安全问题:

简单来说,就是多个线程在操作同一个变量时引起的问题。

这里是用一个简单的例子说明一下:

以Runnable创建的线程为例:一个售票系统,count代表当前票数,卖出一张count--。

Runnable线程类:

  1. public class Runnable_Exp implements Runnable{
  2. private int count = 50;
  3. @Override
  4. public void run() {
  5. while(true)
  6. if(count >= 0){
  7. System.out.println(Thread.currentThread().getName() +"现在的数:"+count);
  8. count--;
  9. }else break;
  10. }
  11. }

在main调用数个相同的Runnable线程:

  1. Runnable_Exp rExp = new Runnable_Exp();
  2. Thread trs1 = new Thread(rExp,"线程1");
  3. Thread trs2 = new Thread(rExp,"线程2");
  4. Thread trs3 = new Thread(rExp,"线程3");
  5. Thread trs4 = new Thread(rExp,"线程4");
  6. trs1.start();trs2.start();trs3.start();trs4.start();

运行:

我们会发现一个问题,票数会有相同的!

这就是线程安全的体现。此时我们就需要使用线程锁解决这个问题。

另外,我们之前学习的集合类中,有分线程安全与线程不安全的两类。

StringBuffer和Vector是线程安全的。

StringBuilder和ArrayList是线程不安全的。

在多线程中,我们不可以使用多个线程同时操作不安全的集合类


线程锁的使用:synchronized

Runnable中使用线程锁:

我们只需要修改一下Runnable线程类。

  1. public class Runnable_Exp implements Runnable{
  2. private int count = 500;
  3. private Object lock = new Object();
  4. @Override
  5. public void run() {
  6. while(true)
  7. synchronized (lock) {
  8. if (count >= 0) {
  9. System.out.println(Thread.currentThread().getName() + "现在的数:" + count);
  10. count--;
  11. } else break;
  12. }
  13. }
  14. }

解析:

添加一个线程锁对象,一般使用Object即可。

  1. private Object lock = new Object();

这个Object对象lock是四个线程共享的(且这个lock一定是共用的!)可以自己尝试一下把锁放进run()中。

  1. synchronized (lock)

当线程一运行到上面这一行的时候,线程一就会占用lock对象(相当于上锁了),直到线程一执行完synchronized语句块内的全部代码,lock对象就会取消占用。

若线程二运行到synchronized语句时,发现lock对象已经被占用了,则会等待,直到lock被取消占用。

有可能多个线程一起抢占。

效率会比较低。毕竟是你执行完再到我执行。无法同步执行。这就是所谓“抢占式”执行。

Thread中使用线程锁:

Thread线程类中:

  1. public class Thread_Exp extends Thread {
  2. public Thread_Exp(){}
  3. public Thread_Exp(String name){
  4. super(name);
  5. }
  6. private static Object lock = new Object();
  7. private static int count = 100;
  8. public void run(){
  9. while(true)
  10. synchronized(lock){
  11. if (count >= 0) {
  12. System.out.println(Thread.currentThread().getName() + "现在的数:" + count);
  13. count--;
  14. } else break;
  15. }
  16. }
  17. }

需要注意的是,这里的线程锁对象和count都需要设置为静态的!

  1. Thread_Exp t1 = new Thread_Exp("线程1");
  2. Thread_Exp t2 = new Thread_Exp("线程2");
  3. Thread_Exp t3 = new Thread_Exp("线程3");
  4. Thread_Exp t4 = new Thread_Exp("线程4");
  5. t1.start();t2.start();t3.start();t4.start();

不创建Object对象可以实现相同的操作吗?

答案是可以的,我们可以不用创建Object类型的lock对象。

我们直接用synchronized(this)就可以了。

相当于检测当前对象是非被线程占用了(加锁)。

实例:

  1. @Override
  2. public void run() {
  3. synchronized (this){
  4. while(true)
  5. if (count >= 0) {
  6. System.out.println(Thread.currentThread().getName() + "现在的数:" + count);
  7. count--;
  8. } else break;
  9. }
  10. }

我们还可以直接使用synchronized关键字描述一个方法,具体请看下文。


使用synchronized方法简化上述代码:

同步方法,顾名思义,就是自带线程锁的方法。

只需要在方法的返回值前面添加synchronized关键字即可。

原先的代码我们可以写成:

使得run()方法更加简洁。

  1. @Override
  2. public void run() {
  3. Count();
  4. }
  5. public synchronized void Count(){
  6. while(true)
  7. if (count >= 0) {
  8. System.out.println(Thread.currentThread().getName() + "现在的数:" + count);
  9. count--;
  10. } else break;
  11. }

使用同步方法,这个方法体就会自动被加锁。


关于线程安全的方法:

上面我们说了StringBuffer方法是线程安全的,那我们是怎么知道的呢?

我们可以直接查看StringBuffer中方法的源代码。

例如attend方法:

  1. @Override
  2. @IntrinsicCandidate
  3. public synchronized StringBuffer append(char c) {
  4. toStringCache = null;
  5. super.append(c);
  6. return this;
  7. }

我们可以看到这个方法是synchronized方法。

大家可以自行去研究一下各种Java自带的方法,是否是线程安全的。

【Java】学习路径47-线程锁synchronized的更多相关文章

  1. 【Java】学习路径48-线程锁ReentrantLock

    与上一章学习的线程锁synchronized类似,都是为了解决线程安全的问题. 使用方法: 新建一个ReentrantLock对象.(如果使用Thread多线程,则需要声明static静态) 然后在需 ...

  2. Java学习路径及练手项目合集

    Java 在编程语言排行榜中一直位列前排,可知 Java 语言的受欢迎程度了. 实验楼上的[Java 学习路径]中将首先完成 Java基础.JDK.JDBC.正则表达式等基础实验,然后进阶到 J2SE ...

  3. java学习笔记15--多线程编程基础2

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note15.html,转载请注明源地址. 线程的生命周期 1.线程的生命周期 线程从产生到消亡 ...

  4. Java学习路径(抛光砖)

    这就是我刚刚在五孔问答中找到的Java学习路线图抛光砖价格.我个人认为,这条Java学习路线是可以的.它是2018年相对较新的Java学习路线,更符合企业就业标准. Java学习路径的第一阶段:Jav ...

  5. java学习笔记14--多线程编程基础1

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note14.html,转载请注明源地址. 多线程编程基础 多进程 一个独立程序的每一次运行称为 ...

  6. 深入理解java:2.2. 同步锁Synchronized及其实现原理

    同步的基本思想 为了保证共享数据在同一时刻只被一个线程使用,我们有一种很简单的实现思想,就是 在共享数据里保存一个锁 ,当没有线程访问时,锁是空的. 当有第一个线程访问时,就 在锁里保存这个线程的标识 ...

  7. 【转】Java学习---深入理解线程池

    [原文]https://www.toutiao.com/i6566022142666736131/ 我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很 ...

  8. Java学习路径:不走弯路,这是一条捷径

    1.如何学习编程? JAVA是一种平台.也是一种程序设计语言,怎样学好程序设计不只适用于JAVA,对C++等其它程序设计语言也一样管用.有编程高手觉得,JAVA也好C也好没什么分别,拿来就用.为什么他 ...

  9. 【Java并发系列04】线程锁synchronized和Lock和volatile和Condition

    img { border: solid 1px } 一.前言 多线程怎么防止竞争资源,即防止对同一资源进行并发操作,那就是使用加锁机制.这是Java并发编程中必须要理解的一个知识点.其实使用起来还是比 ...

随机推荐

  1. Weakmap详解

    先看一个例子 let obj = { name: 'toto' } // { name: 'toto' }这个对象能够被读取到,因为obj这个变量名有对它的引用 // 将引用覆盖掉 obj = nul ...

  2. Java 泛型中的通配符

    本文内容如下: 1. 什么是类型擦除 2.常用的 ?, T, E, K, V, N的含义 3.上界通配符 < ?extends E> 4.下界通配符 < ?super E> 5 ...

  3. 游戏启动后提示安装HMS Core,点击取消,未再次提示安装HMS Core(初始化失败返回907135003)

    问题描述 我们国内的华为联运游戏集成华为游戏服务SDK 之后,被审核驳回:在未安装或需要更新华为移动服务(HMS Core)的手机上,提示安装华为移动服务,点击取消,未再次提示安装HMS Core. ...

  4. 《SVDNet for Pedestrian Retrieval》理解

    <SVDNet for Pedestrian Retrieval>理解 Abstract: 这篇文章提出了一个用于检索问题的SVDNet,聚焦于在行人再识别上的应用.我们查看卷积神经网络中 ...

  5. 基于YCbCr色彩模型的简易肤色识别器

    一.实验方法 实验共选取了12张图像,利用画笔工具在每幅图像上选取5个点,并分别记录RGB值.取点方式如下图所示:        总共70个点,R,G,B的值分别如下表所示: RGB色彩模型和YCbC ...

  6. IO流原理及流的分类

    IO原理 I/O是Input/Output的缩写, I/O技术是非常实用的技术,用于 处理设备之间的数据传输.如读/写文件,网络通讯等. Java程序中,对于数据的输入/输出操作以"流(st ...

  7. javascript基本属性访问对象的属性和方法

    var myName = "Shelley"; //字符串基本类型 alert(myName.length);  //隐式创建String对象,数值与myName相同,并执行len ...

  8. github package的使用教程

    一.写在前面 上一次,笔者向大家介绍了把gitlab仓库作为npm私包的使用方法,具体的详见我的博文地址https://www.cnblogs.com/cnroadbridge/p/16406476. ...

  9. Identity Server 4资源拥有者密码认证控制访问API

    基于上一篇文章中的代码进行继续延伸,只需要小小的改动即可,不明白的地方可以先看看本人上一篇文章及源码: Identity Server 4客户端认证控制访问API 一.QuickStartIdenti ...

  10. MVCC - Read View的可见性判断理解

    读了 @SnailMann大佬[MySQL笔记]正确的理解MySQL的MVCC及实现原理 收益颇丰,非常感谢! 但对其中如何判断事务是否可见性还是不太理解,于是作了本文,在原博客基础上,举例画图论证. ...