您的位置:首页 > 其它

张孝祥[致敬]-多线程学习第03课-线程的互斥与同步

2016-11-08 22:03 225 查看

本文地址:http://blog.csdn.net/hblfyla/article/details/53089014

1.线程的互斥

        为什么会有线程的互斥?可以想银行取款的问题,如果不做监控,多个人同时针对一个存折取钱的时候就会出现钱不对的问题,

下面我们通过两个例子来分析一下线程的互斥问题以及为什么会产生这个线程?

例子1:一个人生产信息,一个人消费信息

          面向对象的思想:类 信息类 生产者 消费者

代码:
package org.yla.lxh.day03;
/**
* 传统线程互斥问题
*
* @author yangluan 2016年11月8日下午9:05:13
*/
public class TriditionalThreadSafeLxh {
public static void main(String[] args) {
// 多个线程调用同一个对象,会带来数据错乱线程,产生的原因分析:
// 多个线程调用一个对象的某个方法
Info info = new Info();
Production p = new Production(info);
Consumer c = new Consumer(info);
new Thread(p).start();
new Thread(c).start();
}
}
class Info {
private String name = "李兴华";
private String content = "讲师";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
class Production implements Runnable {
private Info info;

public Production(Info info) {
this.info = info;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if (i % 2 == 0) {
this.info.setName("李兴华");
try {
Thread.sleep(80);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.info.setContent("讲师");
}else{
this.info.setName("mldn");
try {
Thread.sleep(80);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.info.setContent("www.mldn.cn");
}
}
}
}
class Consumer implements Runnable{
private Info info;

public Consumer(Info info) {
this.info = info;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(80);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.info.getName()+","+this.info.getContent());
}
}

}
   运行:
mldn,讲师
李兴华,www.mldn.cn
mldn,讲师
李兴华,www.mldn.cn
mldn,讲师
李兴华,www.mldn.cn
mldn,讲师
李兴华,www.mldn.cn
mldn,讲师
李兴华,www.mldn.cn
mldn,讲师
李兴华,www.mldn.cn
mldn,讲师
李兴华,www.mldn.cn
mldn,讲师
李兴华,www.mldn.cn
mldn,讲师
李兴华,www.mldn.cn
mldn,讲师
mldn,www.mldn.cn


例子2:多个线程同时打印名字

          面向对象:打印输出类 

代码:
package org.yla.zxx.day03;
/**
* 传统线程互斥问题例子2
* 多个线程同时打印不同人名字
* @author yangluan
* 2016年11月8日下午9:28:09
*/
public class TraditionalThreadSafe {

public static void main(String[] args) {
new TraditionalThreadSafe().init();
}

public void init(){
final OutputMessage c = new OutputMessage();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(120);
} catch (InterruptedException e) {
e.printStackTrace();
}
c.output("aaaaa");
}
}).start();

new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(120);
} catch (InterruptedException e) {
e.printStackTrace();
}
c.output("bbbbb");
}
}).start();

}

class OutputMessage{
public void output(String name){
while(true){
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));//打印一个人的名字
}
System.out.println();
}
}
}
}

  运行;
bbbbb
bbbbb
aaaa
aabbbbb
bbbbb
bbbbb

    通过上面两个例子我们分析得出线程互斥问题产生的原因:

    (1)多个线程调用同一个对象的某个方法

    (2)在线程的run()方法中使用sleep更好的显示出数据错乱线程


2.现在已经产生了互斥问题

     怎么解决上面的问题?
            既然产生的原因是在调用这个对象的方法时候造成互斥,那么我就在这个方法或者代码块实现同步
      下面用例子2看一下解决的办法:
代码:
package org.yla.zxx.day04;
/**
* 传统线程互斥问题例子2
* 多个线程同时打印不同人名字
* @author yangluan
* 2016年11月8日下午9:28:09
*/
public class TraditionalThreadSafe {

public static void main(String[] args) {
new TraditionalThreadSafe().init();
}

public void init(){
final OutputMessage c = new OutputMessage();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(120);
} catch (InterruptedException e) {
e.printStackTrace();
}
c.output("aaaaa");
}
}).start();

new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(120);
} catch (InterruptedException e) {
e.printStackTrace();
}
c.output("bbbbb");
}
}).start();

}

class OutputMessage{
public synchronized void output(String name){
//			synchronized (this) {
while(true){
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));//打印一个人的名字
}
System.out.println();
}
//			}

}
}
}

运行:
bbbbb
bbbbb
bbbbb
bbbbb
bbbbb


3.分析一下使用Synchronized在不同地方的使用

    (1)同步代码块调用的是当前对象

    (2)在方法上使用同步调用的当前对象

    (3)在静态static方法上使用同步调用的类.class,因为静态方法是类直接调用,锁就是这个类的字节码

本文地址:http://blog.csdn.net/hblfyla/article/details/53089014

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: