多线程编程资源争用问题

一 基本概念

     (1)服务器执行任务必须等上一个任务执行完后,才执行下一个任务,称为同步(Synchronized)。上一个任务发出要执行的命令,此时服务器也可以接受其执行命令,也就是说在接受任务后,服务器也可以干其他事称为异步。

 同步和异步的区别 
 举个例子:普通B/S模式(同步)AJAX技术(异步)
同步:提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事
异步: 请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕

     (2)实现实现多线程编程的两种方法:

     A.继承类Thread(所属的jar包 java.lang.Thread)。重写run方法。简单例子

     Publicclass ThreadA extends Thread{

     Publicvoid run(){//重写方法

       Sleep();//直接调用因为继承自父类 父类中含有这个方法

}

     Publicvoid main(String []ars)

{

       ThreadA thread=new Thread();

       Thread.start();//这里直接调用方法即可

     }

}

B.实现接口 Runnable,重写run方法。简单例子:

Public class ThreadB implements Runnable{

     Publicvoid run(){//重写方法

      Thread.sleep();// 如果需要调用sleep()方法的话,需要Thread静态方法。因为这里只是实现了接口

}

     Publicvoid main(String []ars)

{

       ThreadB threadB=new ThreadB();

       (newThreadB(threadB)).start();//这里使用了装饰者模式注意两种方法启动线程的区别因为只是实现了接口,并没有实现 start方法。

    }

}

(3) 线程概念 以及五个状态

一般操作系统都支持同时运行多个任务,每个任务就是一个程序。系统级别的任务称之为进程,一个程序又可以同时执行多个任务。程序级别的任务称之为线程

线程与进程的具体区别:

http://www.cnblogs.com/lmule/archive/2010/08/18/1802774.html

进程是并发的,OS 将时间划分为若干个时间片,在每个时间片段中执行不

同的任务。OS 尽可能均匀地将时间片分给每个任务,所以在微观上,所有的程序都是走走停停,在宏观上所有程序都在同时运行,这种现象叫做并发。

  线程的五个状态:new,runnable,running, block ,dead.

Thread.yeald() 方法会主动让出此CPU 时间,主动从running 状态回到runnable。但让出的时间不可控。


java中,每个线程都需经历新生(new)、就绪(runnable)、运行(running)、阻塞(block)和死亡(dead)五种状态,线程从新生到死亡的状态变化称为生命周期
new运算符Thread类或其子类建立一个线程对象后,该线程就处于新生状态。
   新生(new)--->就绪(runnable):通过调用start()方法
   就绪(runnable)--->运行(running):处于就绪状态的线程一旦得到CPU,就进入运行状态并自动调用自己的run()方法
   运行--->阻塞:处于运行状态的线程,执行sleep()方法,或等待I/O设备资源,让出CPU并暂时中止自己运行,进入阻塞状态
   阻塞--->就绪:睡眠时间已到,或等待的I/O设备空闲下来,线程便进入就绪状态,重新到就绪队列中等待CPU。当再次获得CPU时,便从原来中止位置开始继续运行。
   运行--->死亡:(1)(正常情况下)线程任务完成
               (2)(非正常状况)线程被强制性的中止,如通过执行stop()destroy()方法来终止一个线程

 

(4)wait sleep notify方法以及synchronized()进程块

 4.1 wait与sleep

Sleep 是线程类(Thread)的方法(调用sleep方法由运行状态进入阻塞状态),它使当前线程在指定时间内,将执行机会给其他线程,但不会释放对象锁。wait 是Object 类的方法,3,此对象调用wait(方调用后会立即释放对象锁,线程挂起也就是说wait下面的程序都不再执行,当其他线程对此对象调用notify后才会执行) 方法导致本线程释放对象锁,只有针对此对象发出notify(或notifyAll)方法后本线程才再次试图获得对象锁并进入运行状态。需要注意notify后不是马上就释放对象锁的,而是在相应的synchronized(){}语句块执行结束,自动释放锁后,JVM会在wait()对象锁的线程中随机选取一线程,赋予其对象锁,唤醒线程,继续执行。这样就提供了在线程间同步、唤醒的操作。Thread.sleep()Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制。

二 实际案例分析

  2.1案例源码

package KFC;

public class Ham {

  static Objectbox=new Object();//监控对象

  static int totalmaterial=10;//可用的材料

  static int sales=0;//销售的个数

  static int production=5;//总共生产了多少个

}

package KFC;

 

public class Hassistant implements Runnable {

    public void sell() {

      

/*注意 这里必须是先加锁 然后再判断。如果是先判断,后加锁,则可能出现异步(和Hmaker同时执行的情况),会导致这里的判断结果不准确。以后在写程序时也应当注意这点,都是先加锁再进行判断。

   下例是错误的,现进行说明:

1.  先判断了Ham.production ==Ham.sales 是否成立,假设成立

2.  这时如果Hmaker也执行,production++,改变了production的数量,注意这时还有汉堡。但是此时Hassistant方法仍然执行了synchronized (Ham.box)操作,告诉顾客已经没汉堡了,导致与实际情况相矛盾。

           if (Ham.production ==Ham.sales) {

synchronized (Ham.box) {

              System.out.println("营业员-" +this.getClass().getName()

                    + ":顾客朋友,汉堡没了,请稍等。。");

              try {

                 Ham.box.wait();//此时整个线程会挂起 if语句外面的也不在执行

                 System.out.println("-----线程挂起-------");

              } catch (Exception e) {

                 e.printStackTrace();

              }

           }

        }

 

*/

           synchronized (Ham.box) {

              if (Ham.production ==Ham.sales) {

                  System.out.println("营业员-" +this.getClass().getName()

                         + ":顾客朋友,汉堡没了,请稍等。。");

                  try {

                    System.out.println("-----线程挂起-------");

                     Ham.box.wait();//此时整个线程会立即被挂起  Ham.box.notify()之前,wait()下的语句都不会再执行

                       System.out.println("营业员重新获取对对象锁");  

                  } catch (Exception e) {

                     e.printStackTrace();

                  }

              }

           }

 

   

       Ham.sales++;

       System.out.println("营业员-:顾客朋友汉堡来了,总共卖了:" + (Ham.sales) + "个,还剩"

              + (Ham.production - Ham.sales) +"个,总生产了" + Ham.production

              + "");

      

    }

 

    @Override

    public void run() {

       while (Ham.production <= Ham.totalmaterial) {

           try {

              sell();

              Thread.sleep(1000);// 1s卖一个

           } catch (InterruptedException e) {

              e.printStackTrace();

           }

 

       }

 

    }

 

}

package KFC;

 

import java.lang.*;

 

public class Hmaker implements Runnable {//厨师

    public void make() {

       synchronized (Ham.box)//对资源进行加锁

       {

           (Ham.production)++;//汉堡数量增加

           System.out.println("厨师-" +this.getClass().getName()

                  +" 总共卖了:" + (Ham.sales)

                  + "个,还剩"+(Ham.production-Ham.sales)+"个,总生产了"+Ham.production+"");

           Ham.box.notify();//资源解锁 这里的解锁是指在同步块完成后才真正的解锁 所以notify后 会继续执行

           System.out.println("--资源解锁了---");

       }

    }

 

    @Override

    public void run() {

       while (Ham.production <= Ham.totalmaterial)//还有材料

       {

             

           try {

              Thread.sleep(3000);// 3s做一个汉堡

           } catch (Exception e) {

              e.printStackTrace();

           }

           this.make();

       }

 

    }

 

}

 

package KFC;

 

public class ThreadTest {

public static void main(String []args)

{

    Hmaker maker=new Hmaker();

    Hassistant assistant=new  Hassistant();

    new Thread(assistant).start();

    new Thread(maker).start();

   

}

}

2.2源码分析

代码执行过程如下:

时间

Hmaker

Hassistant

production

sales

left

1s

 

销售1个

5

1

4

2s

 

销售1个

5

2

3

3s

 

销售1个

5

3

2

4s

生产1个,此时虽然执行了notify方法,没有线程处在wait()对象锁的线程

销售1个

6

4

2

5s

 

销售1个

6

5

1

6s

 

销售1个

6

6

0

7s

 

此时,由于盒子里已经没有汉堡,因此执行wait()方法,释放资源锁,线程挂起进入block状态

 

 

 

8s

生产了一个,执行notify方法,此时,处在wait()对象锁状态的只有Hassistant线程一个。

由block状态先进入runnable状态,获取cpu时间,进入running状态,销售一个

7

7

0

9s

 

此时,由于盒子里已经没有汉堡,因此执行wait()方法,释放资源锁,线程挂起进入block状态

 

 

 

10s

….

11s

 

 

 

 

 

12s

 

 

 

 

 

13s

 

 

 

 

 

14s

 

 

 

 

 

15s

 

 

 

 

 

16s

 

 

 

 

 

17s

 

 

 

 

 

18s

 

 

 

 

 

19s

 

 

 

 

 

20s

 

 

 

 

 

21s

 

 

 

 

 

22s

 

 

 

 

 

23s

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值