Java多线程技术篇--线程的互斥与同步通信

来源:互联网 发布:网络推广软件三尾狐 编辑:程序博客网 时间:2024/05/22 09:46

一、使用银行转账来解释线程安全问题

同一个银行账户,在同一时间发生了转账汇款(解释:你刷卡消费了1000元的同时,你朋友给你转账了2000元)。这个时候是两个线程操作同一个数据,但是线程执行是随机的,没有先后之分,这个问题就引发了线程安全问题。


二、使用synchronized代码块及其原理

Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,

这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。


三、使用synchronized方法

package com.sinwao.thread01;public class ThreadSynchronized {public static void main(String[] args) {new ThreadSynchronized().init();}private void init() {Outputer outputer = new Outputer();new Thread(new Runnable() {@Overridepublic void run() {while (true) {try {Thread.sleep(1000);} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}outputer.output3("Mcgrady");}}}).start();new Thread(new Runnable() {@Overridepublic void run() {while (true) {try {Thread.sleep(1000);} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}outputer.output3("Byrant");}}}).start();}static class Outputer{public void output(String name) {int len = name.length();synchronized (Outputer.class) {for (int i = 0; i < len; i++) {System.out.print(name.charAt(i));}System.out.println();}}public synchronized void output2(String name) {int len = name.length();for (int i = 0; i < len; i++) {System.out.print(name.charAt(i));}System.out.println();}public synchronized static void output3(String name) {int len = name.length();for (int i = 0; i < len; i++) {System.out.print(name.charAt(i));}System.out.println();}}}



四、分析静态方法所使用的同步监视器对象是什么

因为output3是一个静态方法,静态方法要同步,必须要用到锁对象,静态方法运行的时候

不用创建类的实例对象,但是静态方法的字节码对象已经在内存里面了,所以在output中传入Output.class,就可以实现同步。

重点:静态方法只与字节码对象关联  

五、面试题解析

子线程循环10次,接着主线程运行10 0次,再接着子线程循环10次,再接着主线程循环100,如此往复50次。

package com.sinwao.thread01;public class ThreadCommunication {public static void main(String[] args) {Business business = new Business();new Thread(new Runnable() {@Overridepublic void run() { for (int i = 0; i < 50; i++) {/*synchronized (ThreadCommunication.class) {for (int j = 0; j < 10; j++) {System.out.println("子线程第" + j + "次执行,循环次数  " + i);}}*//** * 将这部分代码封装起来,可以很高的解决了synchronized锁的问题 * 讲要用到共同数据(包括同步锁)或者共同算法的若干个方法应该归在同一个类身上 * 这种设计正好体现了高类聚和程序的健壮性 */business.sub(i);}}}).start();/** * 加了synchronized之后,子线程跟主线程互斥 */for (int i = 0; i < 50; i++) {/*synchronized (ThreadCommunication.class) {for (int j = 0; j < 10; j++) {System.out.println("主线程第" + j + "次执行,循环次数  " + i);}}*/business.main(i);}}}

package com.sinwao.thread01;public class Business {private boolean isSubThread = true;public synchronized void sub(int i) {//if (!isSubThread) {while(!isSubThread) {try {this.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}for (int j = 0; j < 10; j++) {System.out.println("子线程第" + j + "次执行,循环次数  " + i);}isSubThread = !isSubThread;this.notify();}public synchronized void main(int i) {//if (isSubThread) {while(isSubThread) {try {this.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}for (int j = 0; j < 100; j++) {System.out.println("主线程第" + j + "次执行,循环次数  " + i);}isSubThread = !isSubThread;this.notify();}/** * 使用if和while的区别 * 查看API的时候发现wait在使用if的时候会出现假唤醒情况,所以官方推荐使用while */}