本文章内容整理自:张孝祥_Java多线程与并发库高级应用视频教程

当两条线程访问同一个资源时,可能会出现安全隐患。以打印字符串为例,先看下面的代码:

//
public class Test2 {
public static void main(String[] args) {
new Test2().init();
} public void init(){
final Outputer c = new Outputer();
Thread thread1 = new Thread(new Runnable() { @Override
public void run() { while (true) {
try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
c.output("aaaaa");
} }
});
thread1.start();
Thread thread2 = new Thread(new Runnable() { @Override
public void run() { while(true){
try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
c.output("bbbbb");
} }
});
thread2.start();
} class Outputer{
public void output(String name){ for (int i = ; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println(); }
}
}

在以上代码中,thread1和thread2都调用了output方法,理想的情况下,当thread1调用output方法时,应该一次性打印完“aaaaa”,而当thread2调用output方法,也是一次性打印完“bbbbb”。但在实际的运行中,会出现打印出诸如“aabbbaaa”这种情况,也就是说,thread1正在调用output方法时,thread2插了进来,两个线程同时操作了一个对象中的同一个方法。

为了避免这种情况,我们要求,当某个线程在调用output方法时,不允许其他线程调用。概括一下,即当某个线程在执行一段代码时,不允许其他线程执行这段代码。我们把这种行为,叫做线程互斥。

要实现线程互斥,最简单的方法就是加同步锁。

加同步锁的方式有两种。

第一种是同步代码块,以上面的代码为例,加同步代码块应该这么加:

    class Outputer{
public void output(String name){
synchronized (this) {
for (int i = ; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
}

在上面的代码中,“synchronized (this)”中的“this”被称为锁栓(也有别的叫法,在这里姑且先这么叫吧)。多个需要互斥的线程必须使用同一个对象当锁栓。在这段代码中,“this”指Outputer对象,而两条线程使用的是同一个Outputer对象,所以可以达到互斥效果。

第二种方式是声明同步方法,写法如下:

        public synchronized void output2(String name){
System.out.println(this.getClass());
for (int i = ; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}

现在有一个问题,加入thread1调用output1,thread2调用output2,可以实现线程互斥吗?

答案是可以的。

同步方法使用的锁栓就是“this”。当同步代码块也使用“this”当锁栓时,这两个地方的代码就共用了同一个对象当锁栓,当某个线程进入其中一个时,另一个也被锁住了,不让其他线程进来。

那么,静态同步方法使用的锁栓是什么呢?

以下面这段代码为例:

    static class Outputer{
public static synchronized void output3(String name){
for (int i = ; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}

它的同步锁是Outputer.class,即类的字节码对象。

最后说一说线程同步和线程互斥的关系。

同步是一种更为复杂的互斥,而互斥是一种特殊的同步。

  也就是说互斥是两个线程之间不可以同时运行,他们会相互排斥,必须等待一个线程运行完毕,另一个才能运行,而同步也是不能同时运行,但他是必须要安照某种次序来运行相应的线程(也是一种互斥)!

  总结:

  互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。

  同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥。

java多线程与线程并发二:线程互斥的更多相关文章

  1. Java 多线程基础(五)线程同步

    Java 多线程基础(五)线程同步 当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题. 要解决上述多线程并发访问一个资源的安全性问题,Java中提供了同步机制 ...

  2. Java多线程基础:进程和线程之由来

    转载: Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够 ...

  3. Java多线程学习(八)线程池与Executor 框架

    目录 历史优质文章推荐: 目录: 一 使用线程池的好处 二 Executor 框架 2.1 简介 2.2 Executor 框架结构(主要由三大部分组成) 2.3 Executor 框架的使用示意图 ...

  4. Java多线程-两种常用的线程计数器CountDownLatch和循环屏障CyclicBarrier

    Java多线程编程-(1)-线程安全和锁Synchronized概念 Java多线程编程-(2)-可重入锁以及Synchronized的其他基本特性 Java多线程编程-(3)-从一个错误的双重校验锁 ...

  5. 1、Java多线程基础:进程和线程之由来

    Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够融会贯通 ...

  6. Java 多线程基础(四)线程安全

    Java 多线程基础(四)线程安全 在多线程环境下,如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线 ...

  7. Java 多线程基础(十一)线程优先级和守护线程

    Java 多线程基础(十一)线程优先级和守护线程 一.线程优先级 Java 提供了一个线程调度器来监控程序启动后进去就绪状态的所有线程.线程调度器通过线程的优先级来决定调度哪些线程执行.一般来说,Ja ...

  8. “全栈2019”Java多线程第十三章:线程组ThreadGroup详解

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

  9. “全栈2019”Java多线程第十一章:线程优先级详解

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

  10. “全栈2019”Java多线程第九章:判断线程是否存活isAlive()详解

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

随机推荐

  1. JavaScript ES6函数式编程(二):柯里化、偏应用和组合、管道

    上一篇介绍了闭包和高阶函数,这是函数式编程的基础核心.这一篇来看看高阶函数的实战场景. 首先强调两点: 注意闭包的生成位置,清楚作用域链,知道闭包生成后缓存了哪些变量 高阶函数思想:以变量作用域作为根 ...

  2. Oracle基于布尔的盲注总结

    0x01 decode 函数布尔盲注 decode(字段或字段的运算,值1,值2,值3) 这个函数运行的结果是,当字段或字段的运算的值等于值1时,该函数返回值2,否则返回3 当然值1,值2,值3也可以 ...

  3. 爬虫4:pdf页面+pdfminer模块+demo

    本文介绍下pdf页面的爬取,需要借助pdfminer模块 demo一般流程: 1)设置url url = 'http://www.------' + '.PDF' 2)requests模块获取url ...

  4. 02--Java Jshell的使用 最适合入门的Java教程

    JShell JShell目标 Java Shell 工具(简称:JShell)是一个用于学习Java编程语言和构建Java代码原型的交互式工具.JShell是一个Read-Evaluate-Prin ...

  5. spring cloud 网关服务

    微服务 网关服务 网关服务是微服务体系里面重要的一环. 微服务体系内,各个服务之间都会有通用的功能比如说:鉴权.安全.监控.日志.服务调度转发.这些都是可以单独抽象出来做一个服务来处理.所以微服务网关 ...

  6. 从零开始把项目发布到NPM仓库中心

    从零开始把项目发布到NPM仓库中心 前期准备 注册账号 https://www.npmjs.com/signup 网易邮箱注册失败,用QQ邮箱成功 使用npm 命令注册(建议使用网页): npm ad ...

  7. C加加学习之路 1——开始

    C++是一门古老而复杂的语言,绝不是一门可以速成的语言,学习它需要有意识的刻意练习和长时间的持续不断的磨练.而大多数人不太能耐得住寂寞,喜欢速成,所以像<21天学通C++>这种书就比较受欢 ...

  8. CCBPM工作流系统中如何在特定的一个步骤,调用起另外一条流程

    关键词: 工作流快速开发平台  工作流设计  业务流程管理   asp.net 开源工作流bpm工作流系统  java工作流主流框架  自定义工作流引擎 需求描述: 1, 操作员在操作最后一个节点时, ...

  9. Java基础(十)接口(interface)

    1.接口的概念 在Java中,接口不是类,而是对类的一组需求描述,这些类要遵从接口描述. 例如:Array类中的sort方法可以对对象数组进行排序,但要求满足下列前提:对象所属的类必须实现了Compa ...

  10. 原版_打字游戏.html

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...