多线程

1、概念

     进程: 正在执行中的程序。每一个进程都是一个执行顺序,或者控制单元。

     线程:  进程中的一个单独的控制单元。

     线程的状态:  线程被创建期、运行期、临时期,冻结期,消亡期。

     单线程:一个单线程,一旦进入某一过程,必须等待正常的返回,并退出这一过程, 下一个线程才能开始这个过程。


2、线程的标识

           Static Thread        currenrThread()  返回对当前正在执行的线程对象的引用

            String                     getName()     返回该线程的名称。

           void                         setName(String name) 或者构造方法。

3、 创建线程       

          1)  继承Thread类执行线程

                          A、 定义继承Thread的类 【用于存储线程运行时的代码】

                         B、复写run方法【自定义run方法】

                         C、启动线程的start方法【启用线程、run方法】。

                             class Threadtest extends Thread{

                                               private Res r

                                       public void Threadtest(Res r) {

                                                    this.r=r

                                   }        

                                          public void run() {

                                    .............

                                   }

                           Thread  t1  = new Thread( new Threadtest(res)).start() ;

        2)  实现Runnable接口

                        A、定义类实现Runnable方法,并复写run方法。

                       B、创建Thread线程对象,并将定义的Runnable子类对象作为参数传给Thread的构造方法。

                       C、 调用线程的start方法。

4      线程安全【接口模式】

                      **    处理共享数据时产生【成员变量、公共资源】

                     **    线程运行的粒子单位是单条语句(比如:i++是两条语句)

           显然,对于共享数据的处理,各线程是接替进行的。如果发生错误,说明接替出现问题。实际上,jvm规定了主内存与线程的工作内存。

           当线程操作某个对象时,执行顺    序如下:
                           (1) 从主存复制变量到当前工作内存 (read and load)
                           (2) 执行代码,改变共享变量值 (use and assign)
                           (3) 用工作内存数据刷新主存相关内容 (store and write)

            线程不能直接为主存中中字段赋值,它会将值指定给工作内存中的变量副本(assign),完成后这个变量副本会同步到主存储区(store- write),

            至于何时同步过去,根据JVM实现系统决定。

                         那么就可能会发生这样的事情:

                                 1):线程a从主存读取x副本到工作内存,工作内存中x值为10
                                 2):线程b从主存读取x副本到工作内存,工作内存中x值为10
                                 3):线程a将工作内存中x加1,工作内存中x值为11
                                 4):线程a将x提交主存中,主存中x为11
                                 5):线程b将工作内存中x值减1,工作内存中x值为9
                                 6):线程b将x提交到中主存中,主存中x为9

             这里我们认为多线程处理不同的代码区域,对于处理同一代码区域的多线程有什么意义呢?

        首先,无法体现效率;其次,共享变量处理事件必须原子化限制。

       java用synchronized关键字做为多线程并发环境的执行有序性的保证手段之一。当一段代码会修改共享变量,

        这一段代码成为互斥区或临界区,为了保证共享变量的正确性,synchronized标示了临界区。

5  、锁   

        一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在java里边就是拿到某个同步对象的锁(一个对象只有一把锁);

                   /***对象不同,所以锁不同,无法同步*/

    1. public class ThreadTest extends Thread {   
    2.     private int threadNo;   
    3.     public ThreadTest(int threadNo) {   
    4.         this.threadNo = threadNo;   
    5.     }   
    6.     public static void main(String[] args) throws Exception {   
    7.         for (int i = 1; i < 10; i++) {   
    8.            new ThreadTest(i).start();   
    9.             Thread.sleep(1);             // 延迟
    10.         }   
    11.      }   
    12.     
    13.     @Override  
    14.      public synchronized void run() {   
    15.         for (int i = 1; i < 10000; i++) {   
    16.             System.out.println("No." + threadNo + ":" + i);   
    17.         }   
    18.      }   
    19.  }  

      如果这个时候同步对象的锁被其他线程拿走了,他(这个线程)就只能等了(线程阻塞在锁池等待队列中)。 取到锁后,他就开始执行同步代码(被synchronized

修饰的代码); 线程执行完同步代码后马上就把锁还给同步对象,其他在锁池中等待的某个线程就可以拿到锁执行同步代码了。这样就保证了同步代码在统一时刻

只有一个线程在执行。 

          总结来说,同步有两种方式,同步块和同步方法:

               1)、对于同步的方法或者代码块来说,必须获得对象锁才能够进入同步方法或者代码块进行操作;
               2)、如果采用method级别的同步,则对象锁即为method所在的对象,如果是静态方法,对象锁即指method所在的Class对象(唯一);
               3)、对于代码块,对象锁即指synchronized(abc)中的abc; 

   JDK 1.5版本之后,Lock ,Condition , single 。      

class BoundedBuffer {
   final Lock lock = new ReentrantLock();   //定义唯一的一个锁对象,
   final Condition notFull  = lock.newCondition();  
   final Condition notEmpty = lock.newCondition();//为锁对象定义监视器Condition,将监视器与锁绑定。
   final Object[] items = new Object[100];
   int putptr, takeptr, count;

   public void put(Object x) throws InterruptedException {
     lock.lock();                                               //拿到锁,开始执行
     try {
      while(true) {     
        while (count == items.length)      
         notFull.await();                                      // 通过count共有变量实现线程间有序进行,wait()会释放锁
       items[putptr] = x; 
       if (++putptr == items.length) putptr = 0;
       ++count;
       notEmpty.signal(); 
                      }                                   //  唤醒指定线程,返回判读count值,进入等待
   } finally {
       lock.unlock();                                        // 释放锁。
     }
   }

   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0) 
         notEmpty.await();
       Object x = items[takeptr]; 
       if (++takeptr == items.length) takeptr = 0;
       --count;
       notFull.signal();
       return x;
     } finally {
       lock.unlock();
     }
   } 
 }

        死锁:A持S1锁,想要S2锁;B持S2锁,想要S1锁。形成僵局

                        synchornized(S1){

                                         synchornized(S2)

                                     }

                         synchornized(lS2){

                                         synchornized(S1)

                                      }

                               Thread  A, B;


6、 线程间通信

              当 多线程处理同一资源,但是操作动作(run())不同,会出现要求线程间有序进行。、

          (1)加锁的原则      

                      1)、多线程代码块涉及Input,Output两个   代码块的Run(),需要加同步锁。

                      2)、要处理好锁的对象问题【哪个对象】。

                      3)同步代码块要最小化

                     4) 单例设计模式

           (2) 利用共享数据通信                    

                                wait()….notify()/notifyAll()….   //暂停,唤醒

                        1)  首先在同步代码块中,执行wait..notify的控制操作。

                        2)  设置控制标签【共享数据flag】。

                        3)  确定该操作组监视器【锁对象】,一个对象只有一把锁。只有同一个锁上的线程,才能被同一个锁唤醒。

 多线程处理时,造成相应的锁数量的增加,给开发带来麻烦。notify,一般唤醒当前线程池中的最早等待的线程【也就是处理同一run() 的线程】。

用notifyAll启动对方线程运行,利用标记控制本方,实现两个线程的交替运行

           小知识:

            sleep() 和 wait()有什么区别?

        sleep 是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用 sleep 不会释放对象锁。

wait是 Object 类的方法,对此对象调用 wait 方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify 方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。




                                 

                   


              

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值