一、同步(synchronized)和异步(asynchronized)
1、同步(synchronized)简单说可以理解为共享的意思,如果资源不是共享的,就没必要进行同步。设置共享资源为同步的话,可以避免一些脏读情况。
2、异步(asynchronized)简单说可以理解为独立不受到其他任何制约。
举个例子:
线程1调用了带有synchronized关键字的方法methodA,线程2调用了异步方法methodB,出现的现象是同时控制台输出 t1,t2。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
package com.ietree.multithread.sync; /** * 多线程之对象同步锁和异步锁Demo * * @author ietree */ public class SynAndAsynDemo { public static void main(String[] args) { final SynAndAsynDemo mo = new SynAndAsynDemo(); Thread t1 = new Thread( new Runnable() { @Override public void run() { mo.methodA(); } }, "t1" ); Thread t2 = new Thread( new Runnable() { @Override public void run() { mo.methodB(); } }, "t2" ); t1.start(); t2.start(); } // 方法A public synchronized void methodA(){ try { System.out.println(Thread.currentThread().getName()); // 休眠4秒 Thread.sleep( 4000 ); } catch (InterruptedException e) { e.printStackTrace(); } } // 方法B public void methodB(){ System.out.println(Thread.currentThread().getName()); } } |
线程1调用了带有synchronized关键字的方法methodA,线程2调用了带有synchronized关键字的方法methodB,出现的现象是首先输出t1,等待4秒之后再输出t2。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
package com.ietree.multithread.sync; /** * 多线程之对象同步锁和异步锁Demo * * @author ietree */ public class SynAndAsynDemo { public static void main(String[] args) { final SynAndAsynDemo mo = new SynAndAsynDemo(); Thread t1 = new Thread( new Runnable() { @Override public void run() { mo.methodA(); } }, "t1" ); Thread t2 = new Thread( new Runnable() { @Override public void run() { mo.methodB(); } }, "t2" ); t1.start(); t2.start(); } // 方法A public synchronized void methodA(){ try { System.out.println(Thread.currentThread().getName()); // 休眠4秒 Thread.sleep( 4000 ); } catch (InterruptedException e) { e.printStackTrace(); } } // 方法B public synchronized void methodB(){ System.out.println(Thread.currentThread().getName()); } } |
结论:
在第一段代码中t1线程先持有object对象的Lock锁,t2线程可以以异步的方式调用对象中的非synchronized修饰的方法,所以同时输出;
在第二段代码中t1线程先持有object对象的Lock锁,t2线程如果在这个时候调用对象中的同步(synchronized)方法则需等待,也就是同步。
二、volatile
作用:volatile关键字的作用是:使变量在多个线程间可见(具有可见性),但是仅靠volatile是不能保证线程的安全性,volatile关键字不具备synchronized关键字的原子性。
Demo1:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
package com.ietree.multithread.sync; public class RunThread extends Thread { // volatile private boolean isRunning = true ; private void setRunning( boolean isRunning) { this .isRunning = isRunning; } public void run() { System.out.println( "进入run方法.." ); int i = 0 ; while (isRunning == true ) { // .. } System.out.println( "线程停止" ); } public static void main(String[] args) throws InterruptedException { RunThread rt = new RunThread(); rt.start(); Thread.sleep( 1000 ); rt.setRunning( false ); System.out.println( "isRunning的值已经被设置了false" ); } } |
程序输出:
1
2
3
4
|
进入run方法.. isRunning的值已经被设置了 false 之后进入死循环 |
Demo2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
package com.ietree.multithread.sync; public class RunThread extends Thread { // volatile private volatile boolean isRunning = true ; private void setRunning( boolean isRunning) { this .isRunning = isRunning; } public void run() { System.out.println( "进入run方法.." ); int i = 0 ; while (isRunning == true ) { // .. } System.out.println( "线程停止" ); } public static void main(String[] args) throws InterruptedException { RunThread rt = new RunThread(); rt.start(); Thread.sleep( 1000 ); rt.setRunning( false ); System.out.println( "isRunning的值已经被设置了false" ); } } |
程序输出:
1
2
|
isRunning的值已经被设置了 false 线程停止 |
总结:当多个线程之间需要根据某个条件确定 哪个线程可以执行时,要确保这个条件在 线程之间是可见的。因此,可以用volatile修饰。
volatile 与 synchronized 的比较:
①volatile轻量级,只能修饰变量。synchronized重量级,还可修饰方法
②volatile只能保证数据的可见性,不能用来同步,因为多个线程并发访问volatile修饰的变量不会阻塞。
synchronized不仅保证可见性,而且还保证原子性,因为,只有获得了锁的线程才能进入临界区,从而保证临界区中的所有语句都全部执行。多个线程争抢synchronized锁对象时,会出现阻塞。
线程安全性包括两个方面,①可见性。②原子性。
从上面自增的例子中可以看出:仅仅使用volatile并不能保证线程安全性。而synchronized则可实现线程的安全性。
以上这篇详谈Java多线程的几个常用关键字就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持服务器之家。