Java中的线程同步
Java 中的线程同步问题:
1. 线程同步:
对于访问同一份资源的多个线程之间, 来进行协调的这个东西.
2. 同步方法:
当某个对象调用了同步方法时, 该对象上的其它同步方法必须等待该同步方法执行完毕后, 才能被执行.
3. 同步块:
通常将共享资源的操作放置在 synchronized 定义的区域内, 这样当其它线程也获取到这个锁时, 必须等待锁被释放, 才能进入该区域.
Demo_1:
class Timer {
private static int num = 0;
public void add(String name) {
num++;
try {
Thread.sleep(100); // 即使不写 Thread.sleep(100), 这个结果可能是对的,也有可能是错的, 不确定. 中间还是有可能被打断.
} catch (InterruptedException e) {
}
System.out.println(name+", 你是第 "+num+"个使用timer的线程");
}
}
class TestSync implements Runnable {
Timer timer = new Timer();
public static void main(String[] args) {
TestSync test = new TestSync();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
@Override
public void run() {
timer.add(Thread.currentThread().getName());
}
}
会出现的运行结果:
t1, 你是第 2个使用timer的线程
t2, 你是第 2个使用timer的线程
原因:这个线程在执行 add()方法的时候, 被另外一个线程给打断了.
解决办法:
num++;
try {Thread.sleep(100);
} catch (InterruptedException e) {}
上面这几句话, 应该作为一个原子性的输出, 你不应该在中途打断.
第一种解决办法:采用同步块, 如 Demo_2
Demo_2:
class Timer {
private static int num = 0;
public void add(String name) {
synchronized(this){ // 同步块
num++;
try {Thread.sleep(100);
} catch (InterruptedException e) {}
System.out.println(name+", 你是第 "+num+"个使用timer的线程");
}
}
}
class TestSync implements Runnable {
Timer timer = new Timer();
public static void main(String[] args) {
TestSync test = new TestSync();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
@Override
public void run() {
timer.add(Thread.currentThread().getName());
}
}
// 运行结果如下:
// t1, 你是第 1个使用timer的线程
// t2, 你是第 2个使用timer的线程
【注】:既然锁定了当前对象了, 那么这个 num 也就锁定了, 它里面的成员变量当然也锁定(互斥锁).
【注】:锁定当前对象:这执行后面的大括号里面的语句的过程中, 一个线程的执行过程中, 不会被另外一个线程锁打断.
一旦某个线程已经进入到锁定的区域当中, 那么你放心, 不可能有另外一个线程也在里面(锁的机制).
第二种解决办法:采用同步块, 如 Demo_3
Demo_3:
class Timer {
private static int num = 0;
public synchronized void add(String name) { //同步方法
num++;
try {Thread.sleep(100);
} catch (InterruptedException e) {}
System.out.println(name+", 你是第 "+num+"个使用timer的线程");
}
}
class TestSync implements Runnable {
Timer timer = new Timer();
public static void main(String[] args) {
TestSync test = new TestSync();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
@Override
public void run() {
timer.add(Thread.currentThread().getName());
}
}
// 运行结果如下:
// t1, 你是第 1个使用timer的线程
// t2, 你是第 2个使用timer的线程
分析 Demo_3 的执行过程:
t1 开始执行, 调用 add() 方法, num++, 然后 t1 睡着了, 睡着了也没关系, t1 睡着也抱着那把锁.
别人(t2)也进不来, 你必须等它执行完了, 你才可以继续执行.
睡着了, 也不放开那把锁, 你也没办法.
4. 线程同步总结:
4.1. 在 Java 语言中, 引入了对象互斥锁的概念, 保证共享数据操作的完整性. 每个对象都对应于一个可称为"互斥锁"的标记,
这个标记保证在任一时刻, 只有一个线程访问该对象.
4.2. 关键字 synchronized 与对象的互斥锁联系. 当某个对象用 synchronized 来修饰时, 表明该对象在任一时刻只能由一个线程访问.
Java中的线程同步的更多相关文章
- java中实现线程同步
为何要使用同步? java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查), 将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他 ...
- Java中处理线程同步
引自:http://blog.csdn.net/aaa1117a8w5s6d/article/details/8295527和http://m.blog.csdn.net/blog/undoner/1 ...
- Java中实现线程同步的三种方法
实现同步的三种方法 多线程共享数据时,会发生线程不安全的情况,多线程共享数据必须同步. 实现同步的三种方法: 使用同步代码块 使用同步方法 使用互斥锁ReetrantLock(更灵活的代码控制) 代码 ...
- Java中的线程同步机制
一.首先为什么线程需要同步? 1.多线程安全问题的原因 A:有多线程环境 B:有共享数据 C:有多条语句操作共享数据 2. //未完待续后面会继续更新
- 浅谈利用同步机制解决Java中的线程安全问题
我们知道大多数程序都不会是单线程程序,单线程程序的功能非常有限,我们假设一下所有的程序都是单线程程序,那么会带来怎样的结果呢?假如淘宝是单线程程序,一直都只能一个一个用户去访问,你要在网上买东西还得等 ...
- 关于Java中的线程安全(线程同步)
java中的线程安全是什么: 就是线程同步的意思,就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对他进行操作了,必须等到这次访问结束以后才能对这个线程安全的方法进行访问 什么叫 ...
- Java中的线程Thread总结
首先来看一张图,下面这张图很清晰的说明了线程的状态与Thread中的各个方法之间的关系,很经典的! 在Java中创建线程有两种方法:使用Thread类和使用Runnable接口. 要注意的是Threa ...
- 关于Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇高质量的博文)
Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇质量高的博文) 前言:在学习多线程时,遇到了一些问题,这里我将这些问题都分享出来,同时也分享了几篇其他博客主的博客,并且将我个人的理解也分享 ...
- Java多线程与线程同步
六.多线程,线程,同步 ①概念: 并行:指两个或多个在时间同一时刻发生(同时发生) 并发:指两个或多个事件在同一时间段内发生 具体概念: 在操作系统中,安装了多个程序,并发指的是在一段时间内宏观上有多 ...
随机推荐
- css 浮动说明
clear:both; 1.要了解的:什么是浮动.浮在某面板之上. 例如:float:left; 向左停靠, 就是让需要设置浮动的元素,跟在指定元素后面. 先上实例: 比较常用导航: .nav_ul ...
- 【Spark】源码分析之SparkContext
一.概述 SaprkContext非常重要,是Spark提交任务到集群的入口 SparkContext中没有main方法,在SparkContext主构造器中,主要做一下四件事情: 1. 调用crea ...
- python--模块之sys与python解释器交互模块
作用:sys模块是与python解释器交互的一个接口.它提供了一系列有关python运行环境的变量和函数. 常用函数:import sys sys.argv #命令行参数list,第一个元素是程序本身 ...
- HyperLedger Fabric 1.4 基础环境搭建(7)
学习了前面几章理论知识后,本章开始介绍实践操作,先介绍Fabric基础环境搭建,采用的操作系统为Centos 7 64位,依次介绍Docker安装.Docker-Compose安装.GO语言环境安装. ...
- Go语言中的变量
1 概述 变量(Variable)是程序运行过程中,内容可以变化(修改)的量,变量的功能是存储用户的数据,是计算机语言中能储存计算结果或能表示值抽象概念.变量,是通过变量的标识符定位值的过程.变量的内 ...
- 在同一台机器上启动多个tomcat服务(转)
转载:https://blog.csdn.net/wangxy799/article/details/53957770 1.案例:配置一台机上配置三个Tomcat 2.方法1:[只用修改第一个以外To ...
- 成都Uber优步司机奖励政策(3月19日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- dubbo之注册管理中心
一.在dubbo的框架中注册中心是必要的一个环节,这个也是分布式部署的一个必要环节.在dubbo的架构基本图中可以看出,基本上所有的服务都是通过注册中心进行注册,然后在通过注册中心,暴露出接口来. 二 ...
- netty之粘包分包的处理
1.netty在进行字节数组传输的时候,会出现粘包和分包的情况.当个数据还好,如果数据量很大.并且不间断的发送给服务器,这个时候就会出现粘包和分包的情况. 2.简单来说:channelBuffer在接 ...
- SpringBoot学习:添加JSP支持
项目下载地址:http://download.csdn.NET/detail/aqsunkai/9805821 (一)pom中添加依赖: <!-- https://mvnrepository.c ...