在Java中,一般都是通过同步机制来解决线程安全问题的,在JDK 5.0之后又新增了Lock的方式来实现线程安全。所以说实现线程安全方式一共有三种方法

方式一:

synchronized(同步监视器){

  //需要被同步的代码(操作共享数据的代码就是需要被同步的代码)

}

通过继承Thread类的方式实现多线程并解决线程安全问题:

 package com.baozi.java;

 public class WinowTest {
public static void main(String[] args){
Window w1=new Window();
Window w2=new Window();
Window w3=new Window();
w1.start();
w2.start();
w3.start();
}
}
//通过继承Thread类的方法来实现多线程
class Window extends Thread {
private static int ticket = 100;
@Override
public void run() {
while (true) {
//这里通过synchronized代码块的形式来实现线程安全
synchronized (Window.class) {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + ticket--);
} else {
break;
}
}
} }
}

通过实现Runnable接口的方式实现多线程并解决线程安全问题:

 package com.baozi.java;

 public class WindowTest2 {
public static void main(String[] args){
Window2 window2 = new Window2();
Thread t1 = new Thread(window2);
Thread t2 = new Thread(window2);
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
} }
//通过实现Runnable接口的方式实现多线程
class Window2 implements Runnable{
private int ticket = 100;
@Override
public void run() {
while (true) {
//这里通过synchronized代码块的形式来实现线程安全
synchronized (this) {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + ticket--);
} else {
break;
}
}
} }
}

备注:

  同步监视器:其实就是我们平时说的锁,任何一个类对象都可以充当同步监视器,并且针对需要操作的共享数据,要求多个线程必须共享同一个同步监视器,这样才能实现多线程共享数据的线程安全。

  同步方法解决了线程安全问题,但是在操作同步代码块的时候,实质上某一时刻只有一个线程拥有锁,其他线程需要操作共享数据的时候只能等待该线程释放了所之后通过抢占方式获得锁之后才能执行。言外之意针对共享数据其实是单线程执行,这样会造成效率非常低。

方式二:

如果多个线程操作的共享数据的代码完整的声明在一个方法中,那么我们使用synchronized关键字修饰这个方法为同步方法。

通过继承Thread类的方式实现多线程并解决线程安全问题:

 package com.baozi.java;

 public class WindowTest3 {
public static void main(String[] args) {
Window3 w1 = new Window3();
Window3 w2 = new Window3();
Window3 w3 = new Window3();
w1.start();
w2.start();
w3.start();
}
} //通过继承Thread类的方法来实现多线程
class Window3 extends Thread {
private static int ticket = 100; @Override
public void run() {
while (true) {
show();
}
} //这里通过synchronized方法的形式来实现线程安全
public static synchronized void show() {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + ticket--);
}
}
}

通过实现Runnable接口的方式实现多线程并解决线程安全问题:

 package com.baozi.java;

 public class WindowTest2 {
public static void main(String[] args) {
Window2 window2 = new Window2();
Thread t1 = new Thread(window2);
Thread t2 = new Thread(window2);
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
//通过实现Runnable接口的方式实现多线程
class Window2 implements Runnable {
private int ticket = 100; @Override
public synchronized void run() {
while (true) {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + ticket--);
} else {
break;
}
}
}
}

备注:同步方法依然会涉及到同步监视器,只是不需要我么显示的声明。

  非静态的同步方法:同步监视器可以是this(当前对象)

  静态的同步方法:同步监视器可以是当前类

这样我们就能省去单独造一个对象来充当同步监视器,使代码比较简单整洁。

方式三:

使用Lock锁的方式实现线程安全,这是JDK5.0新增加的方法,在后边单独分析。

synchronized关键字的详细分析和代码实例的更多相关文章

  1. Java:多线程,线程同步,synchronized关键字的用法(同步代码块、非静态同步方法、静态同步方法)

    关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象.本文探讨synchronized关键字. sy ...

  2. 【智能算法】粒子群算法(Particle Swarm Optimization)超详细解析+入门代码实例讲解

    喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 01 算法起源 粒子群优化算法(PSO)是一种进化计算技术(evolutionary computation),1995 年由E ...

  3. Java精通并发-Lock与synchronized关键字在底层的区别及实例分析

    在上两次中已经将Lock这个接口的整个官方说明进行了阅读,这次来了解一下它的一个非常重要的实现类: 啥叫“可重入”呢?其实是指一个线程已经拿到了锁,然后该线程还能再次获取这把锁,接下来在了解它之前先用 ...

  4. java动态代理实现与原理详细分析(代码层面解释了AOP的实现)

    关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 一.代理模式    代理模式是常用的java设计模式, ...

  5. Apriori算法第二篇----详细分析和代码实现

    1 Apriori介绍 Apriori算法使用频繁项集的先验知识,使用一种称作逐层搜索的迭代方法,k项集用于探索(k+1)项集.首先,通过扫描事务(交易)记录,找出所有的频繁1项集,该集合记做L1,然 ...

  6. Spring 注解详细分析解释有实例

    概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作.如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO ...

  7. hibernate缓存机制详细分析 复制代码 内部资料 请勿转载 谢谢合作

    您可以通过点击 右下角 的按钮 来对文章内容作出评价, 也可以通过左下方的 关注按钮 来关注我的博客的最新动态. 如果文章内容对您有帮助, 不要忘记点击右下角的 推荐按钮 来支持一下哦 如果您对文章内 ...

  8. 管理后台界面 详细分析(内含代码 |【前端】)RuoYi

    最近在做的一个后台管理 因为关于隐私原因 只方便展示个别页面代码 不会上传项目 注意是前端代码 我把项目代码地址放在最后了 如有需要可自取学习   我会为各位兄弟详细的介绍其中各个属性的含义和用法,记 ...

  9. Java精通并发-透过字节码理解synchronized关键字

    在上一次https://www.cnblogs.com/webor2006/p/11428408.html中对于synchronized关键字的作用做了一个实例详解,下面再来看一下这个程序: 请问下, ...

随机推荐

  1. Linux环境安装jdk12-rpm

    此博客只是本人的个人学习记录,若有什么误导观看者,请不要怪我... 1.环境准备: Linux环境:Centos7 jdk版本:JavaSE12      下载地址:https://www.oracl ...

  2. java中import详解

    前言 import与package机制相关,这里先从package入手,再讲述import以及static import的作用. package package名称就像是我们的姓,而class名称就像 ...

  3. day 18 - 2 正则与 re 模块练习

    1.爬虫的例子 #爬虫的例子(方法一) import re import urllib,request import urlopen def getPage(url): response = urlo ...

  4. css 实现加载中3个点跳动

    <style type="text/css">.loading:after { overflow: hidden; display: inline-block; ver ...

  5. 软件测试-Svn服务器搭建全过程-基于Centos6.7-64bit

    本文详细介绍了在CentOs6.7-64bit服务器上搭建SVN版本控制服务 工具准备 CentOs6.7-64bit操作系统:关闭linux防火墙:设置定固IP--DHCP(动态):安装系统过程中开 ...

  6. dubbo直连提供者 & 只订阅 & 只注册

    1.    dubbo直连提供者 在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连,点对点直连方式,将以服务接口为单位,忽略注册中心的提供者列表,A 接口配置点 ...

  7. Python爬虫案例-获取最新的中国行政区域划分

    源网页:中国统计局标准 http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2016/ 打开网页后可以分析出行政区域划分共分为5层 根据传入参数,生成网页 ...

  8. java 日常学习记录

    前言:记录自己初学java 遇到的问题. 环境(win10  开始安装的IDEA,net 开发者  )学习网址:http://how2j.cn/stage/14.html (不是打广告) 特别是对初学 ...

  9. [吐槽]webpack4

    https://webpack.js.org/guides/tree-shaking/ https://www.webpackjs.com/guides/ 插件都过时被替代了,中文文档也没更新过来,坑 ...

  10. NOIP2018Day1T1 铺设道路

    题目描述 春春是一名道路工程师,负责铺设一条长度为 \(n\) 的道路. 铺设道路的主要工作是填平下陷的地表.整段道路可以看作是 \(n\) 块首尾相连的区域,一开始,第 \(i\) 块区域下陷的深度 ...