一、关于线程安全

1.是什么决定的线程安全问题?
  线程安全问题基本是由全局变量静态变量引起的。
  若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

2.可以解决多线程并发访问资源的方法有哪些?
  主要有三种方式:分别是同步代码块 、同步方法和锁机制(Lock)
  其中同步代码块和同步方法是通过关键字synchronized实现线程同步

本文主要是将synchronized关键字用法作为例子来去解释Java中的对象锁和类锁

二、synchronized关键字各种用法与实例

  事实上,synchronized修饰非静态方法、同步代码块的synchronized (this)用法和synchronized (非this对象)的用法锁的是对象,线程想要执行对应同步代码,需要获得对象锁。

synchronized修饰静态方法以及同步代码块的synchronized (类.class)用法锁的是类,线程想要执行对应同步代码,需要获得类锁。

因此,事实上synchronized关键字可以细分为上面描述的五种用法。
1.同步块synchronized (this)

public class Ticket1 extends Thread{

    private int nums = 0; //出票数
private int count =20; //剩余 @Override
public void run() {
while (true) {
synchronized (this) {
if(count <= 0) {
break;
}
nums++;
count--;
try {
Thread.sleep(550);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("显示出票信息:"+Thread.currentThread().getName()+
"抢到第"+nums+"张票,剩余"+count+"张");
}
}
} public static void main(String[] args) {
Ticket1 ticket1 = new Ticket1();
Thread anni = new Thread(ticket1,"安妮");
Thread jack = new Thread(ticket1,"jack");
anni.start();
jack.start(); } }

这样是同步的,线程获取的是同步块synchronized (this)括号()里面的对象实例的对象锁,这里就是Ticket1 实例对象的对象锁了。

需要注意的是synchronized (){}的{}前后的代码依旧是异步的

2.synchronized (非this对象)的用法锁的是对象

例1:

public class Ticket2 implements Runnable{

	private int nums = 0; //出票数
private int count =25; //剩余
//实现线程安全三种方法
private final Object lock = new Object();//1.使用私有不变对象锁,使得攻击者无法获取到锁对象(推荐使用) @Override
public void run() {
while (true) {
//2.this 使用对象自身的锁(隐式锁)--对象锁
//3.Ticket2.class 给Ticket2加锁 --类锁->使用说明:静态方法则一定会同步,非静态方
//法需在单例模式才生效(本例为单例),但是也不能都用静态同步方法,总之用得不好可能会给性能带来极大的影响。
synchronized (lock) {
if(count <= 0) {
break;
}
nums++;
count--;
try {
Thread.sleep(750);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("显示出票信息:"+Thread.currentThread().getName()+
"抢到第"+nums+"张票,剩余"+count+"张");
}
}
} public static void main(String[] args) {
Ticket2 ticket2 = new Ticket2();
Thread zhangsan = new Thread(ticket2,"张三");
Thread zhaoyun = new Thread(ticket2,"赵云");
zhangsan.start();
zhaoyun.start();
} }

例2:

public class Run2 {

    public static void main(String[] args) {

        Service service = new Service("xiaobaoge");

        ThreadA2 a = new ThreadA2(service);
a.setName("A");
a.start(); ThreadB2 b = new ThreadB2(service);
b.setName("B");
b.start(); } } class Service { String anyString = new String(); public Service(String anyString){
this.anyString = anyString;
} public void setUsernamePassword(String username, String password) {
try {
synchronized (anyString) {
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入同步块");
Thread.sleep(3000);
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开同步块");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} } class ThreadA2 extends Thread {
private Service service; public ThreadA2(Service service) {
super();
this.service = service;
} @Override
public void run() {
service.setUsernamePassword("a", "aa"); } } class ThreadB2 extends Thread { private Service service; public ThreadB2(Service service) {
super();
this.service = service;
} @Override
public void run() {
service.setUsernamePassword("b", "bb"); } }

3.synchronized (class)

public class Run {

    public static void main(String[] args) {

        ThreadA a = new ThreadA();
a.setName("A");
a.start(); ThreadB b = new ThreadB();
b.setName("B");
b.start(); } }
class Service { public static void printA() {
synchronized (Service.class) {
try {
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入printA");
Thread.sleep(3000);
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开printA");
} catch (InterruptedException e) {
e.printStackTrace();
}
} } public static void printB() {
synchronized (Service.class) {
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入printB");
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开printB");
}
}
}

4.静态synchronized同步方法  

public class Run {

    public static void main(String[] args) {

        ThreadA a = new ThreadA();
a.setName("A");
a.start(); ThreadB b = new ThreadB();
b.setName("B");
b.start(); } } class Service { synchronized public static void printA() {
try {
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "进入printA");
Thread.sleep(3000);
System.out.println("线程名称为:" + Thread.currentThread().getName()
+ "在" + System.currentTimeMillis() + "离开printA");
} catch (InterruptedException e) {
e.printStackTrace();
}
} synchronized public static void printB() {
System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "进入printB");
System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
+ System.currentTimeMillis() + "离开printB");
} } class ThreadA extends Thread {
@Override
public void run() {
Service.printA();
} } class ThreadB extends Thread {
@Override
public void run() {
Service.printB();
}
}

5.synchronized修饰非静态方法

public class Run {

    public static void main(String[] args) {

        HasSelfPrivateNum numRef = new HasSelfPrivateNum();

        ThreadA athread = new ThreadA(numRef);
athread.start(); ThreadB bthread = new ThreadB(numRef);
bthread.start(); } }
class HasSelfPrivateNum { private int num = 0; synchronized public void addI(String username) {
try {
if (username.equals("a")) {
num = 100;
System.out.println("a set over!");
Thread.sleep(2000);
} else {
num = 200;
System.out.println("b set over!");
}
System.out.println(username + " num=" + num);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class ThreadA extends Thread { private HasSelfPrivateNum numRef; public ThreadA(HasSelfPrivateNum numRef) {
super();
this.numRef = numRef;
} @Override
public void run() {
super.run();
numRef.addI("a");
} }
class ThreadB extends Thread { private HasSelfPrivateNum numRef; public ThreadB(HasSelfPrivateNum numRef) {
super();
this.numRef = numRef;
} @Override
public void run() {
super.run();
numRef.addI("b");
} }

实验结论:两个线程访问同一个对象中的同步方法是一定是线程安全的。本实现由于是同步访问,所以先打印出a,然后打印出b

这里线程获取的是HasSelfPrivateNum的对象实例的锁——对象锁。

 

java线程同步以及对象锁和类锁解析(多线程synchronized关键字)的更多相关文章

  1. (删)Java线程同步实现二:Lock锁和Condition

    在上篇文章(3.Java多线程总结系列:Java的线程同步实现)中,我们介绍了用synchronized关键字实现线程同步.但在Java中还有一种方式可以实现线程同步,那就是Lock锁. 一.同步锁 ...

  2. 【Thread】java线程之对象锁、类锁、线程安全

    说明: 1.个人技术也不咋滴.也没在项目中写过线程,以下全是根据自己的理解写的.所以,仅供参考及希望指出不同的观点. 2.其实想把代码的github贴出来,但还是推荐在初学的您多亲自写一下,就没贴出来 ...

  3. Java锁Synchronized,对象锁和类锁举例

    Java的锁分为对象锁和类锁. 1. 当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内针对该对象的操作只能有一个线程得到执行.另一个线程必须 ...

  4. Java锁Synchronized对象锁和类锁区别

    java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁.线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁.获得内置锁的唯一途径就是进入这个锁的保 ...

  5. Java对象锁和类锁全面解析(多线程synchronized关键字)

    最近工作有用到一些多线程的东西,之前吧,有用到synchronized同步块,不过是别人怎么用就跟着用,并没有搞清楚锁的概念.最近也是遇到一些问题,不搞清楚锁的概念,很容易碰壁,甚至有些时候自己连用没 ...

  6. java的对象锁和类锁

    在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看这个关键字的用法. 因为synchronized关键字涉及到锁的概念,所以先来了解一些相关的锁知识. j ...

  7. java 对象锁和类锁的区别(转)

    java 对象锁和类锁的区别   转自; ) ); ; ) ); 上述的代码,第一个方法时用了同步代码块的方式进行同步,传入的对象实例是this,表明是当前对象,当然,如果需要同步其他对象实例,也不可 ...

  8. Java 中对象锁和类锁的区别? 关键字 Synchronized的用法?

    一  对象锁和类锁的关系 /* * 对象锁和[类锁] 全局锁的关系? 对象锁是用于对象实例方法,或者一个对象实例上的 this 类锁是用于类的静态方法或者一个类的class对象上的. Ag.class ...

  9. Java线程池的原理及几类线程池的介绍

    刚刚研究了一下线程池,如果有不足之处,请大家不吝赐教,大家共同学习.共同交流. 在什么情况下使用线程池? 单个任务处理的时间比较短 将需处理的任务的数量大 使用线程池的好处: 减少在创建和销毁线程上所 ...

随机推荐

  1. 致Python初学者,Python常用的基础函数你知道有哪些吗?

    Python基础函数: print()函数:打印字符串 raw_input()函数:从用户键盘捕获字符 len()函数:计算字符长度 format(12.3654,'6.2f'/'0.3%')函数:实 ...

  2. composer 忽略版本检测

    今天安装插件的时候,直接不能安装,提示其他插件版本要求 tip:心细的朋友可能发现黄色部分提示了,提示我们升级composer,现在composer2.0已经发布了,赶快升级吧传送门 https:// ...

  3. jquery中请求格式

    $.ajax({ url:"/ceshi/", type:"get", cache:false, dataType:"json", data ...

  4. 把之前CompletableFuture留下的坑给填上。

    你好呀,我是歪歪. 填个坑吧,把之前一直欠着的 CompletableFuture 给写了,因为后台已经收到过好几次催更的留言了. 这玩意我在之前写的这篇文章中提到过:<面试官问我知不知道异步编 ...

  5. 《手把手教你》系列技巧篇(二十九)-java+ selenium自动化测试- Actions的相关操作上篇(详解教程)

    1.简介 有些测试场景或者事件,Selenium根本就没有直接提供方法去操作,而且也不可能把各种测试场景都全面覆盖提供方法去操作.比如:就像鼠标悬停,一般测试场景鼠标悬停分两种常见,一种是鼠标悬停在某 ...

  6. caffe转换变量时的gflags问题

    先解决错误7,解决方式来自于http://blog.csdn.net/wishchin/article/details/51888566这篇博文,感谢博主 只需要添加上 #pragma comment ...

  7. 下载cnki硕博士论文的pdf版

    每找到一篇心仪的硕博士论文时,总是迫不及待下载到本地吧. 可是接下来你只能选择caj格式. caj界面都用过吧,没用过,你也不会来这. 我就想看pdf版本的,怎么办呢?有办法! 重点来了,敲黑板: 1 ...

  8. Initialize this repository with a README

    在gitHub创建项目时,有很多小伙伴不太清楚 Initialize this repository with a README 在什么情况下需要勾选,在这里简单说明 如下: 1. 翻译 如果要导入现 ...

  9. 关于dp那些事

    拿到一道题,先写出状态转移方程,再优化时间复杂度 状态优化: 对于状态可累加 \(e.g.dp[i+j]=dp[i]+dp[j]+i+j\) 的,用倍增优化 决策优化: \(e.g.dp[i][j]= ...

  10. redis两种持久化策略/存储模式

    redis的持久化策略   RDB,即 Redis DataBase,以快照形式将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的dump文件,达到数据恢复. 默认开启,见redis ...