synchronized

  Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。然而,当一个线程访问object的一个加锁代码块时,另一个线程仍然可以访问该object中的非加锁代码块。

                                                        ——以上来源百度百科

一、方法内的变量为线程安全

“非线程安全”的问题存在于“实例变量”中,如果是方法内部的私有变量,则不会存在“非线程安全”问题,所得结果就是“线程安全”的了。

MyService类

 1 package com.mythread.www.day8.testSyn.ep1;
 2
 3 public class MyService {
 4     public void add(String name) {
 5         try {
 6             int num = 0;
 7             if (name.equals("a")) {
 8                 num = 100;
 9                 System.out.println("a is over");
10                 Thread.sleep(1000);
11             } else {
12                 num = 200;
13                 System.out.println("b is over");
14             }
15             System.out.println(name + " num = " + num);
16         } catch (InterruptedException e) {
17             e.printStackTrace();
18         }
19     }
20 }

线程类A

 1 package com.mythread.www.day8.testSyn.ep1;
 2
 3 public class ThreadA extends Thread {
 4     private MyService service;
 5
 6     public ThreadA(MyService service) {
 7         super();
 8         this.service = service;
 9     }
10
11     @Override
12     public void run() {
13         service.add("a");
14     }
15 }

线程类B

 1 package com.mythread.www.day8.testSyn.ep1;
 2
 3 public class ThreadB extends Thread {
 4     private MyService service;
 5
 6     public ThreadB(MyService service) {
 7         super();
 8         this.service = service;
 9     }
10
11     @Override
12     public void run() {
13         service.add("b");
14     }
15 }

运行类

 1 package com.mythread.www.day8.testSyn.ep1;
 2
 3 public class Run {
 4     public static void main(String[] args) {
 5         MyService service = new MyService();
 6         ThreadA threadA = new ThreadA(service);
 7         threadA.start();
 8         ThreadB threadB = new ThreadB(service);
 9         threadB.start();
10     }
11 }

结果

1 a is over
2 b is over
3 b num = 200
4 a num = 100

从运行结果来看,方法中的变量不存在非线程安全的问题,永远都是线程安全的,这事方法内部的变量是私有的特性造成的。

二、实例变量非线程安全

MyService类

 1 package com.mythread.www.day8.testSyn.ep1;
 2
 3 public class MyService {
 4     private int num = 0;
 5     public void add(String name) {
 6         try {
 7
 8             if (name.equals("a")) {
 9                 num = 100;
10                 System.out.println("a is over");
11                 Thread.sleep(1000);
12             } else {
13                 num = 200;
14                 System.out.println("b is over");
15             }
16             System.out.println(name + " num = " + num);
17         } catch (InterruptedException e) {
18             e.printStackTrace();
19         }
20     }
21 }

线程类和运行类同上,运行结果

1 a is over
2 b is over
3 b num = 200
4 a num = 200

产生这个结果的原因是两个线程同事访问同一个没有同步的方法,如果两个对象同时操作对象中的实例变量,可能会造成非线程安全的问题

最简单的解决方案是在方法的前面加个synchronized同步锁

MyService类

 1 package com.mythread.www.day8.testSyn.ep1;
 2
 3 public class MyService {
 4     private int num = 0;
 5     synchronized public void add(String name) {
 6         try {
 7
 8             if (name.equals("a")) {
 9                 num = 100;
10                 System.out.println("a is over");
11                 Thread.sleep(1000);
12             } else {
13                 num = 200;
14                 System.out.println("b is over");
15             }
16             System.out.println(name + " num = " + num);
17         } catch (InterruptedException e) {
18             e.printStackTrace();
19         }
20     }
21 }

线程类和运行类同上,运行结果

1 a is over
2 a num = 100
3 b is over
4 b num = 200

在两个线程访问同一个对象中的同步方法时一定是线程安全的,上面的代码由于时同步访问,所以先打印出a,然后在打印出b

改一下运行类,其他类同上

 1 package com.mythread.www.day8.testSyn.ep1;
 2
 3 public class Run {
 4     public static void main(String[] args) {
 5         MyService serviceA = new MyService();
 6         MyService serviceB = new MyService();
 7         ThreadA threadA = new ThreadA(serviceA);
 8         threadA.start();
 9         ThreadB threadB = new ThreadB(serviceB);
10         threadB.start();
11     }
12 }

结果

1 a is over
2 b is over
3 b num = 200
4 a num = 100

这是两个线程分别访问同一个类的两个不同实例的相同名称的同步方法,效果却是以异步的形式来执行的。

因为创建了两个业务对象,在系统中产生了两个锁,所以运行结果是异步的。

关键字synchronized所取得的锁都是对象锁,而不是把一段代码或者方法当作锁。

My Service类

 1 package com.mythread.www.day8.testSyn.ep1;
 2
 3 public class MyService {
 4     synchronized public void methodA() {
 5         try {
 6             System.out.println("begin methodA threadName = " + Thread.currentThread().getName());
 7             Thread.sleep(3000);
 8             System.out.println("end methodA time = " + System.currentTimeMillis());
 9         } catch (InterruptedException e) {
10             e.printStackTrace();
11         }
12     }
13
14     public void methodB() {
15         try {
16             System.out.println("begin methodB threadName = " + Thread.currentThread().getName());
17             Thread.sleep(3000);
18             System.out.println("end methodB time = " + System.currentTimeMillis());
19         } catch (InterruptedException e) {
20             e.printStackTrace();
21         }
22     }
23 }

线程类A

 1 package com.mythread.www.day8.testSyn.ep1;
 2
 3 public class ThreadA extends Thread {
 4     private MyService service;
 5
 6     public ThreadA(MyService service) {
 7         super();
 8         this.service = service;
 9     }
10
11     @Override
12     public void run() {
13         service.methodA();
14     }
15 }

线程类B

 1 package com.mythread.www.day8.testSyn.ep1;
 2
 3 public class ThreadB extends Thread {
 4     private MyService service;
 5
 6     public ThreadB(MyService service) {
 7         super();
 8         this.service = service;
 9     }
10
11     @Override
12     public void run() {
13         service.methodB();
14     }
15 }

运行类

 1 package com.mythread.www.day8.testSyn.ep1;
 2
 3 public class Run {
 4     public static void main(String[] args) {
 5         MyService service = new MyService();
 6         ThreadA threadA = new ThreadA(service);
 7         threadA.start();
 8         ThreadB threadB = new ThreadB(service);
 9         threadB.start();
10     }
11 }

结果

1 begin methodA threadName = Thread-1
2 begin methodB threadName = Thread-2
3 end methodB time = 1458400534384
4 end methodA time = 1458400534384

在My Service的methodB前面也加上关键字synchronized

My Service类

 1 package com.mythread.www.day8.testSyn.ep1;
 2
 3 public class MyService {
 4     synchronized public void methodA() {
 5         try {
 6             System.out.println("begin methodA threadName = " + Thread.currentThread().getName());
 7             Thread.sleep(3000);
 8             System.out.println("end methodA time = " + System.currentTimeMillis());
 9         } catch (InterruptedException e) {
10             e.printStackTrace();
11         }
12     }
13
14     synchronized public void methodB() {
15         try {
16             System.out.println("begin methodB threadName = " + Thread.currentThread().getName());
17             Thread.sleep(3000);
18             System.out.println("end methodB time = " + System.currentTimeMillis());
19         } catch (InterruptedException e) {
20             e.printStackTrace();
21         }
22     }
23 }

结果

1 begin methodA threadName = Thread-1
2 end methodA time = 1458400619034
3 begin methodB threadName = Thread-2
4 end methodB time = 1458400622035

对比上面两次代码的运行结果。

在第一次运行时,当A线程先持有My Service的同步锁时,B线程可以已异步的方式去调用My Service对象中的非synchronized方法。

在第二次运行时,当A线程先持有My Service的同步锁时,当B想调用My Service对象中的synchronized,则需要先等A释放对象锁。

所以,synchronized锁住的时对象,而不是其他的一些东西。

三、synchronized锁重入

当一个线程获得一个对象锁后,再次请求此对象锁时是可以再次获得此对象锁的

My Service类

 1 package com.mythread.www.day8.testSyn.ep1;
 2
 3 public class MyService {
 4     synchronized public void methodA() {
 5         System.out.println("methodA");
 6         methodB();
 7     }
 8
 9     synchronized public void methodB() {
10         System.out.println("methodB");
11         methodC();
12     }
13
14     synchronized public void methodC() {
15         System.out.println("methodC");
16     }
17 }

线程类

1 package com.mythread.www.day8.testSyn.ep1;
2
3 public class MyThread extends Thread {
4     @Override
5     public void run() {
6         MyService myService = new MyService();
7         myService.methodA();
8     }
9 }

运行类

1 package com.mythread.www.day8.testSyn.ep1;
2
3 public class Run {
4     public static void main(String[] args) {
5         MyThread myThread = new MyThread();
6         myThread.start();
7     }
8 }

结果

1 methodA
2 methodB
3 methodC

自己还可以重新获得自己的内部锁,如果不可以的话,上面的这个Demo则会造成死锁现象

Main类

 1 package com.weishiyao.learn.day4.testThread;
 2
 3 public class Main {
 4     public int i = 10;
 5     synchronized public void operateIMainMethod() {
 6         try {
 7             i--;
 8             System.out.println("main print i=" + i);
 9             Thread.sleep(100);
10         } catch (Exception e) {
11             e.printStackTrace();
12         }
13     }
14 }

Sub类

 1 package com.weishiyao.learn.day4.testThread;
 2
 3 public class Sub extends Main{
 4     synchronized public void operateISubMethod() {
 5         try {
 6             while (i > 0) {
 7                 i--;
 8                 System.out.println("sub print i=" + i);
 9                 Thread.sleep(100);
10                 this.operateIMainMethod();
11             }
12         } catch (Exception e) {
13             e.printStackTrace();
14         }
15     }
16 }

线程类

1 package com.weishiyao.learn.day4.testThread;
2
3 public class MyThread  extends Thread{
4     @Override
5     public void run() {
6         Sub sub = new Sub();
7         sub.operateISubMethod();
8     }
9 }

运行类

1 package com.weishiyao.learn.day4.testThread;
2
3 public class Run {
4     public static void main(String[] args) {
5         MyThread t = new MyThread();
6         t.run();
7     }
8 }

结果

 1 sub print i=9
 2 main print i=8
 3 sub print i=7
 4 main print i=6
 5 sub print i=5
 6 main print i=4
 7 sub print i=3
 8 main print i=2
 9 sub print i=1
10 main print i=0

当存在父子类继承关系时,子类完全可以通过父类“可重入锁”调用父类的同步方法

转载于:https://www.cnblogs.com/babycomeon/p/5293710.html

java多线程(二)——锁机制synchronized(同步方法)相关推荐

  1. Java多线程的同步机制(synchronized)

    一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在 java里边就是拿到某个同步对象的锁(一个对象只有一把锁): 如果这个时候同步对象的锁被其他线程拿走了,他(这个 ...

  2. Java多线程,锁(CAS,synchronized,AQS,ReentrantLock)

    该博客只是个人学习的笔记.如果有什么疑问或者有什么不对的都可以告诉我,目前只写了多线程和锁的部分,因为只是个人学习记录的笔记,所以写的不是很详细,里面有一些个人的见解思考供各位参考. 一.多线程 关于 ...

  3. 【java线程】锁机制:synchronized、Lock、Condition

    [Java线程]锁机制:synchronized.Lock.Condition 原创 2013年08月14日 17:15:55 标签:Java /多线程 74967 http://www.infoq. ...

  4. 12【多线程、锁机制、lock锁】

    上一篇:11[泛型.Map.异常] 下一篇:13[线程等待.状态.线程池.File类] 目录:[JavaSE零基础系列教程目录] 12[多线程.锁机制.lock锁] 一.多线程概念 在实际应用中,多线 ...

  5. java实验多线程机制_使用Java多线程的同步机制编写应用程序 PDF 下载

    使用Java多线程的同步机制编写应用程序 PDF 下载 本站整理下载: 相关截图: 主要内容: 一. 实验名称 使用Java多线程的同步机制编写应用程序 二. 实验目的及要求 1.理解并行/并发的概念 ...

  6. Java中的锁机制 -- 乐观锁、悲观锁、自旋锁、可重入锁、读写锁、公平锁、非公平锁、共享锁、独占锁、重量级锁、轻量级锁、偏向锁、分段锁、互斥锁、同步锁、死锁、锁粗化、锁消除

    文章目录 1. Java中的锁机制 1.1 乐观锁 1.2 悲观锁 1.3 自旋锁 1.4 可重入锁(递归锁) 1.5 读写锁 1.6 公平锁 1.7 非公平锁 1.8 共享锁 1.9 独占锁 1.1 ...

  7. java多线程互斥锁_浅谈Java多线程互斥锁

    为了解决竞争条件带来的问题,我们可以对资源上锁.多个线程共同读写的资源称为共享资源,也叫临界资源.涉及操作临界资源的代码区域称为临界区(Critical Section).同一时刻,只能有一个线程进入 ...

  8. java线程 锁_Java多线程(二) 多线程的锁机制

    当两条线程同时访问一个类的时候,可能会带来一些问题.并发线程重入可能会带来内存泄漏.程序不可控等等.不管是线程间的通讯还是线程共享数据都需要使用Java的锁机制控制并发代码产生的问题.本篇总结主要著名 ...

  9. java多线程:线程同步synchronized(不同步的问题、队列与锁),死锁的产生和解决

    0.不同步的问题 并发的线程不安全问题: 多个线程同时操作同一个对象,如果控制不好,就会产生问题,叫做线程不安全. 我们来看三个比较经典的案例来说明线程不安全的问题. 0.1 订票问题 例如前面说过的 ...

最新文章

  1. 嵌入式系统linux之光标隐藏解决
  2. VSFTP配置参数详解
  3. ivy java_使用Ivy管理项目中的依赖
  4. sql报表按月统计_如何通过INTOUCH组态软件做EXCEL报表(含代码)
  5. Java基础18(类加载、反射和动态代理)
  6. 洛谷P3338:力(FFT)
  7. class h5 点击后样式变化_【php】JQuery怎么实现页面刷新后保留鼠标点击addclass的样式?...
  8. Android打包出多个dex文件,一个APK中包含多个dex方法
  9. java--Date时间
  10. Appium下载及环境搭建
  11. 制作数据库导出模板,导出数据库设计说明书
  12. 银行业金融机构数据治理指引和DCMM的对比分析
  13. 鼎立测试软件能锁网吗,路测软件鼎利通信Pioneer操作培训PPT(ET128).ppt
  14. 查看win10的产品密钥过期时间
  15. 1-10000内的素数c语言,输入1-10000的素数
  16. 阿里云IoT千里传音之声连网互动营销服务,首次亮相!
  17. git不能push文件
  18. MiniUI Api 方法
  19. 什么是jQuery,jquery的特点
  20. 2018.8.9日,预习笔记,Linux软件包安装和卸载

热门文章

  1. jsp 修改的员工select怎么_jsp修改的时候下拉框怎么取修改数据的值?
  2. java工具类,常用的那些方法
  3. cpanel java_Cpanel是什么
  4. hashmap修改对应key的值_死磕 java集合之HashMap源码分析
  5. Babelfish (关于mapstring,string的用法
  6. java中逗号分隔的字符串和List相互转换
  7. Java中System.nanoTime()的使用
  8. java button随机颜色_Javascript点击按钮随机改变数字与其颜色
  9. python导出excel数据表中追加数据_python pandas在已存在的excel中追加数据
  10. metasploit下载教程linux,在Debian 10/9系统上安装Metasploit Framework的方法