java多线程学习
2015-08-22 11:25
218 查看
从今天开始学习java多线程,平时自己写的程序很少用到多线程,也导致对于多线程这里一直不是很理解,接下来着重研究多线程。
Resource.java
A.java
B.java
代码比较简单,这里A和B线程使用的是同一个资源,A资源设置resource的值,B线程获取resource的值。这里为了保证A,B两个线程操作的是同一个资源,使用了通过构造方法来初始化。为了区分效果,这里A线程分别设置不同的值。
测试代码:
此时打印结果如下:
可以看到这里就出现了线程安全问题。为什么会出现这样的问题呢??比如A线程对name赋值为jerry之后,还没来得及给sex设置woman值,此时线程的执行权就被B线程获取到了,所以会获取到的是”jerry======男孩”
A.java
B.java
这里操作的都是同一个对象,resource,为了保证两个线程使用的同一个锁,所以synchronized中的对象必须唯一,这里使用了resoure对象保证唯一性。
此时输出结果如下:
可以看到此时已经正常输出了。
这里在Resource.java中定义一个标记,由于该标记必须唯一,所以放在了Resource.java中,用来标记当前线程是否可以获取执行权:
此时A线程的run方法如下:
B线程的run方法如下:
此时运行的效果如下:
多线程的安全问题
当我们有多个线程对同一个资源进行操作的时候,就会出现多线程安全问题,比如,A线程对一个资源设置值,B线程从同样的资源获取A资源设置的值,有可能在A没有完全设置完成,B线程就获取了执行权,此时就会出现多线程安全问题,这样说,大家可能不太理解,看下代码:Resource.java
package com.test.safe; public class Resource { String name; String sex; }
A.java
package com.test.safe; public class A implements Runnable { private Resource resource; public A(Resource resource) { this.resource = resource; } @Override public void run() { boolean isEng = true; while(true) { if (isEng) { resource.name = "jerry"; resource.sex = "woman"; isEng = false; } else { resource.name = "杰瑞"; resource.sex= "男孩"; isEng = true; } } } }
B.java
package com.test.safe; public class B implements Runnable { private Resource resource; public B(Resource resource) { this.resource = resource; } @Override public void run() { while (true) { System.out.println(resource.name+"======="+resource.sex); } } }
代码比较简单,这里A和B线程使用的是同一个资源,A资源设置resource的值,B线程获取resource的值。这里为了保证A,B两个线程操作的是同一个资源,使用了通过构造方法来初始化。为了区分效果,这里A线程分别设置不同的值。
测试代码:
Resource resource = new Resource(); new Thread(new A(resource)).start(); new Thread(new B(resource)).start();
此时打印结果如下:
可以看到这里就出现了线程安全问题。为什么会出现这样的问题呢??比如A线程对name赋值为jerry之后,还没来得及给sex设置woman值,此时线程的执行权就被B线程获取到了,所以会获取到的是”jerry======男孩”
解决线程安全问题
我们可以在两个线程操作同一个资源的地方使用synchronized为其加上锁即可。A.java
synchronized (resource) { if (isEng) { resource.name = "jerry"; resource.sex = "woman"; isEng = false; } else { resource.name = "杰瑞"; resource.sex= "男孩"; isEng = true; } }
B.java
synchronized (resource) { System.out.println(resource.name+"======="+resource.sex); }
这里操作的都是同一个对象,resource,为了保证两个线程使用的同一个锁,所以synchronized中的对象必须唯一,这里使用了resoure对象保证唯一性。
此时输出结果如下:
可以看到此时已经正常输出了。
等待唤醒机制
虽然我们加了同步锁可是大家又没有发现,有一个问题,就是每次输出一大片中文,在输出一大片英文,如果我们想设置一个,在输出一个,应该怎么实现??这里就需要使用到等待唤醒机制。这里在Resource.java中定义一个标记,由于该标记必须唯一,所以放在了Resource.java中,用来标记当前线程是否可以获取执行权:
package com.test.safe; public class Resource { String name; String sex; boolean flag = false; }
此时A线程的run方法如下:
@Override public void run() { boolean isEng = true; while(true) { synchronized (resource) { if (resource.flag) {//如果当前flag==true,表示B线程正在执行,此时需要等待,等待期间,后边的代码是不会执行的。 try { resource.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } if (isEng) { resource.name = "jerry"; resource.sex = "woman"; isEng = false; } else { resource.name = "杰瑞"; resource.sex= "男孩"; isEng = true; } resource.flag = true; //A线程设置数据执行结束,将flag设置为true,表示线程池中的其他线程可以获得线程的执行权了 resource.notify(); //唤醒使用同一个锁的线程,这里就是B线程 } } }
B线程的run方法如下:
@Override public void run() { while (true) { synchronized (resource) { if (!resource.flag) {//B线程正好和A线程相反 try { resource.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(resource.name+"======="+resource.sex); resource.flag = false; resource.notify(); } } }
此时运行的效果如下:
相关文章推荐
- JAVA内存分配-通俗讲解
- JAVA基础概念
- Java多线程通信
- Struts(19)Struts集成
- Struts(18)标签
- Java Servlet的配置文件web.xml配置内容和具体含义
- Spring Filter components in auto scanning
- java 金额转大写
- Struts(17)注释
- Struts简介
- Spring Auto scanning components
- Java-7-数组
- Struts(16)异常处理
- Java-6-IO
- java SWT中Label实时刷新当前时间
- Java-5-异常
- Struts(15)类型转换
- Java-4-重载多态
- Struts(14)本地化/国际化(i18n)
- Struts(13)验证框架