【线程】同步线程和协作线程

  • 同步线程
    为解决多线程争用统一资源的争用问题,我们常用synchronized关键字修饰的方法来解决。 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类。
  • 同步是多线程中的重要概念。同步的使用可以保证在多线程运行的环境中,程序不会产生设计之外的错误结果。同步的实现方式有两种,同步方法和同步块,这两种方式都要用到synchronized关键字。
  • 同步方法:

(1)同步块
代码实现:

package edu.xalead;

public class 吃包子 extends Thread {
   private 包子类 p = null;

   private String name = null;

   public 吃包子(包子类 p,String name){
       this.p = p;
       this.name = name;
   }

//   public synchronized void eat(){
//       //if (this.p.pack <= 0) break;
//       // synchronized (p) {
//           System.out.println(this.name + "吃第" + this.p.pack + "个包子");
//           this.p.pack--;
//
//   }
   public void run(){
     try {
       while(true) {
//            synchronized (p) {   // 同步监视器     同步块   加锁计数器为0,线程可执行对象,为1,堵塞,不能执行
           // p : 多个线程共同访问的同一个对象
//               if (this.p.pack <= 0) break;
//               System.out.println(this.name + "吃第" + this.p.pack + "个包子");
//               this.p.pack--;
//           Thread.sleep(10);
           // 控制当前线程类休息

          // if (this.p.pack <= 0) break;
           //---
           if(p.eat(this.name))  break;
           Thread.sleep(10);
       }

     } catch (InterruptedException e) {
         e.printStackTrace();
     }
           /**
            * 多线程的争用问题:
            * 会出现两个线程共享一个对象时,一线程封装完,但没执行this.p.pack--;
            * 导致另一线程到了分时执行时重复执行,但实际上,一对象只能使用或调用一次
            * 解决该问题的思想:加锁,一线程使用一对象完成后,再进行另一线程的具体操作。
            */

(2) 同步方法
代码实现:

package edu.xalead;

public class 包子类 extends edu.xalead.comunication.包子类 {
    /**
     * 同步方法监视的对象是this.
     */
    public int pack = 100;
    //public 吃包子 a = null;   关联
    //同步方法
    public synchronized boolean  eat(String name) {

        if (this.pack <= 0) return true;
        System.out.println(name + "吃第" + this.pack + "个包子");
        //this.pack--;
        --this.pack;
        return false;

    }
}

  • 代码测试:
package edu.xalead;

public class Test {                               // 线程的争用
    public static void main(String[] args) {

        包子类 p = new 包子类();

        吃包子 q = new 吃包子(p,"vbrwa");
        q.start();
        吃包子 q2 = new 吃包子(p,"Danny");
        q2.start();
    }
}

  • 运行结果:
    1-100个包子
  • 线程写作的实例化及实现:
package edu.xalead.comunication;
import edu.xalead.comunication.做包子;

public class 做包子 extends Thread{

    private 包子类 p = null;
    private String name = null;

    public 做包子(包子类 p, String name){
        this.p = p;
        this.name = name;
    }

    public void run(){
        try {

            while(true) {
                synchronized (p) {
                    if (p.pack <= 0) {
                        p.pack = 100;
                        System.out.println(this.name + "做好了" + p.pack + "个包子");
                    } else {
                        p.notifyAll();  // 唤醒线程
                        //p.notify();
                        p.wait();    //释放锁 释放时间

                    }
                }
            }
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

package edu.xalead.comunication;

public class 包子类 {

    public int pack = 1000;

}

package edu.xalead.comunication;

public class 吃包子 extends Thread {

    private 包子类 p = null;
    private String name = null;

    public 吃包子(包子类 p, String name) {
        this.p = p;
        this.name = name;
    }


    public void run() {
//       long start = System.currentTimeMillis();
        try {
//           for(int i =0;i<10000000;i++)/*while (true)*/ {
               synchronized (p) {
                   //p : 多个线程共同访问的同一个对象
                   if (this.p.pack <= 0) {
                       //p.notifyAll();
                       p.wait();  //监视对象释放锁,线程数改为0
                       p.notify();  //唤醒做包子的

                   }else{
                       System.out.println(this.name + "吃第" + this.p.pack + "个包子");
                       this.p.pack--;
                   }
               }
               Thread.sleep(1);

       } catch (InterruptedException e) {
                 e.printStackTrace();
       }

代码测试:

package edu.xalead.comunication;

import edu.xalead.包子类;
import edu.xalead.吃包子;

public class Test {                               // 线程的征用
    public static void main(String[] args) {
        包子类 p = new 包子类();

        做包子 mr = new 做包子(p,"王大厨");
        吃包子 q = new 吃包子(p,"vbrwa");
        吃包子 q2 = new 吃包子(p,"Danny");

        q.start();
        q2.start();
        mr.start();
    }
}

运行结果:
在这里插入图片描述
p.wait(); 释放锁,线程数改为0; p.notify(); 唤醒(做包子的)对象。
线程之间的协作可以大大减少线程等待的时间,提高了效率。

发布了101 篇原创文章 · 获赞 47 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/TONGZONGE/article/details/94591047