Java基础学习之线程

来源:互联网 发布:博客园app网络异常 编辑:程序博客网 时间:2024/05/22 17:40

一、“监视线程”通讯模型

概念:同时多个独立线程在运行,运行状态由第三方监控线程全程监控,这种模型为监视线程模型

如下所示:

二、线程同步问题

多线程程序可能存在的一个问题就是:可能会出现多个线程同时操作某一个对象的数据,结果就会出现线程对象对自己操作的数据不同步的情况。

如图:



例子:

package com.test.thread;/** * 账户类 *  * @author lhz *  */public class Account {private int count;public Account(int count) {this.count = count;}/** * 取现的方法 */public int getCount(int cash) {// synchronized (this) {if (count < cash) {System.out.println("你的余额不足,余额为" + count + "取现失败");return -1;}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}count = count - cash;// }return count;}}
package com.test.thread;/** * 客户线程类 *  * @author lhz *  */public class Costomer extends Thread {private Account account;private int cash;private String type;public Costomer(Account account, int cash, String type) {this.cash = cash;this.account = account;this.type = type;}/** * 取现 */public void run() {int result = account.getCount(cash);if (result < 0) {System.out.println(type + "取现失败,您余额不足");} else {System.out.println(type + "取现成功,您取了" + cash + ",余额还有" + result);}}}
package com.test.thread;public class ThreadTest {public static void main(String[] args) {Account account = new Account(5000);Costomer c1 = new Costomer(account, 4000, "atm");Costomer c2 = new Costomer(account, 3000, "柜台");c1.start();c2.start();}}
会出现这里两种情况





第一张图:这个是因为,程序先执行c2.start(),调用getCount(int cash)方法,执行到休眠;c1.start()执行,执行到休眠;c2又执行,执行

count = count - cash;
此时count=2000;但是c1的count还是5000,然后c1执行
count = count - cash;
此时count=1000,最终 count=1000.
第二张图:这个是因为,程序先执行c1.start(),调用getCount(int cash)方法,执行到休眠;c2.start()执行,执行到休眠;c1又执行,执行

count = count - cash;
此时count=1000;但是c1的count还是5000,然后c1执行

count = count - cash;
此时count=2000,最终 count=2000.

不管是那种情况,对于银行来说都是亏本的,如何解决这个问题呢?

三、synchronized:同步锁关键字,锁定当前对象或者方法,一家独用

简介:

1、synchronized代码块中的语句只能有一个线程在执行      

2、任意一个对象都有一个标志位,有1和0两种状态
3、当程序执行到synchronized代码块的时候线程会检查对象的标志位是1还是0

4、如果是1则执行程序,同是将对象的标志位设置为0,其他线程执行到synchronized代码块时一看对象标志位为0 则线程会阻塞,一直等到对象的标志位为1再执行下面的程序 

实例(还是上面的例子):锁定同一个对象

synchronized (this) {if (count < cash) {System.out.println("你的余额不足,余额为" + count + "取现失败");return -1;}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}count = count - cash;}
四、 wait/notify机制
       在java中,每个对象都有从Object父类继承而来的两个关于线程间通讯的方法wait()和notify(),如其方法名所示,一个是等待,一个是通知,当在一个对象上调用wait()方法时,当前线程就会进行wait状态,直到收到另一个对象的notify()发出通知,才会执行下一步计算

        在多线程通讯中,经常会用对象的这两个方法,一个典型的案例就是“生产/消费者模型”

五、生产/消费者模型

模型规则
        生产和消费线程共同操作一个集合,生产线程放入对象,消费线程取出对象!仅当集合中没有对象时,生产线程会放入一个对象,如有集合中有一个对象时,消费线程要马上取出这个对象。

如图所示 :


实例:

package com.test.thread1;/** * 手机类 *  * @author lhz *  */public class Phone {public int type;}

package com.test.thread1;import java.util.ArrayList;/** * 消费者 *  * @author lhz *  */public class Costomer extends Thread {private Phone phone;private ArrayList<Phone> list;public Costomer(Phone phone, ArrayList<Phone> list) {this.phone = phone;this.list = list;}public void run() {while (true) {// synchronized (list) {if (list.size() >= 1) {list.remove(0);// 取出// list.notify();System.out.println("消费了" + phone.type);phone.type++;} else {continue;// try {// list.wait();// 等待// } catch (InterruptedException e) {// e.printStackTrace();// }}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}// }}}}
package com.test.thread1;import java.util.ArrayList;/** * 生产者 *  * @author lhz *  */public class Product extends Thread {private Phone phone;private ArrayList<Phone> list;public Product(Phone phone, ArrayList<Phone> list) {this.phone = phone;this.list = list;}public void run() {while (true) {// synchronized (list) {if (list.size() <= 0) {list.add(phone);// 放入// list.notify();// 通知System.out.println("生产出" + phone.type);phone.type++;} else {continue;// try {// list.wait();// 等待// } catch (InterruptedException e) {// e.printStackTrace();// }}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}// }}}}
package com.test.thread1;import java.util.ArrayList;public class TestThread {public static void main(String[] args) {Phone phone = new Phone();ArrayList<Phone> list = new ArrayList<Phone>();Product p = new Product(phone, list);Costomer c = new Costomer(phone, list);p.start();c.start();}}
cpu消耗非常大,效率低



使用了wait/notify,但是没有使用同步锁

while (true) {// synchronized (list) {if (list.size() >= 1) {list.remove(0);// 取出list.notify();System.out.println("消费了" + phone.type);phone.type++;} else {try {list.wait();// 等待} catch (InterruptedException e) {e.printStackTrace();}}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}// }}
while (true) {// synchronized (list) {if (list.size() <= 0) {list.add(phone);// 放入list.notify();// 通知System.out.println("生产出" + phone.type);phone.type++;} else {try {list.wait();// 等待} catch (InterruptedException e) {e.printStackTrace();}}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}// }}



加了同步锁

while (true) {synchronized (list) {if (list.size() <= 0) {list.add(phone);// 放入list.notify();// 通知System.out.println("生产出" + phone.type);phone.type++;} else {try {list.wait();// 等待} catch (InterruptedException e) {e.printStackTrace();}}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}
while (true) {synchronized (list) {if (list.size() >= 1) {list.remove(0);// 取出list.notify();System.out.println("消费了" + phone.type);phone.type++;} else {try {list.wait();// 等待} catch (InterruptedException e) {e.printStackTrace();}}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}
cpu占内存少了,不会出现做无用功情况




注意:

  1)wait和notify必须在同步锁之内使用
  2)同步锁锁定对象和wait、notify对象必须同一个
  3)当对象wait挂起状态时候是会释放同步锁的

六、线程生命周期


1 0
原创粉丝点击