## 多线程

### 1.程序、进程、线程

- 在操作系统中运行的程序就是进程;

- 一个进程可以有多个线程;
- 程序是指令和数据的有序集合,是一个静态的概念;
- 而进程则是执行程序的一次执行过程,是一个动态的概念;
- 进程是系统资源分配的单位
- 线程是CPU调度和执行的单位
- 真正的多线程是指多个cpu,即多核

理解:进程相当于一个类,类中有多个方法(即多个线程),main()方法即(主线程),gc线程。

- main()方法即(主线程)为系统的入口,用于执行整个程序;
- 线程的运行是由调度器安排调度,不能人为干预;
- 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制
- 线程会带来额外的开销,如cpu的调度时间,并发控制开销
- 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

### 2.线程的创建

1. **三种创建方式**

- Thread class

- 继承Thread类

- Runnable接口

- 实现Runnable接口

- Callable接口

- 实现Callable接口

 

### **3.Thread**

- 自定义类继承Thread
- 重写run()方法;
- 创建对象,调用start()开启线程

```java
import javax.xml.transform.Source;public class TestThread01 extends Thread{
    //继承Thread类
//总结:线程开启不一定立即执行,有CPU调度执行    @Override
    public void run() {
        //run()方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("**********-4564646465");
        }
    }    //main线程,即主线程
    public static void main(String[] args) {        TestThread01 testThread01 = new TestThread01();
        //testThread01.start();//线程开启,交替(类似同时)执行,电脑单核只有一个cpu
        testThread01.run();//这个在前,先执行run();
        for (int i = 0; i < 20; i++) {
            System.out.println("7554574545*********");
        }    }

}

```

多线程实现多张图片同时下载

```java
import org.apache.commons.io.FileUtils;import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;public class TestThread02 extends Thread{
    private String url;
    private  String name;   public TestThread02(String url,String name){
       this.url=url;
       this.name=name;
   }
    public TestThread02(){
    }

@Override

public void run() {
       //下载线程
        WebDownloader webDownloader = new WebDownloader();
        try {
            webDownloader.downloader(url,name);
            System.out.println(name);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }    public static void main(String[] args) {
        TestThread02 testThread02 = new TestThread02("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603037822768&di=5f0cc79b7c104781de8cea48c7d8b1ca&imgtype=0&src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2Fmonth_1012%2F10120514509c7244b23f4a2fa5.jpg","a.jpg");
        TestThread02 testThread03 = new TestThread02("https://ns-strategy.cdn.bcebos.com/ns-strategy/upload/fc_big_pic/part-00720-1746.jpg","a1.jpg");
        TestThread02 testThread04 = new TestThread02("https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2441956749,4275399915&fm=26&gp=0.jpg","a2.jpg");
        testThread02.start();
        testThread03.start();
        testThread04.start();
    }}
//下载器
class WebDownloader{
    //下载方法
    public  void  downloader(String url,String name) throws IOException {        FileUtils.copyURLToFile(new URL(url),new File(name));
    }
}

```

### 4.Runnable

推荐使用Runnable对象,因为Java单继承的局限性

1. 定义MyRunnable类实现Runnable接口
2. 实现run()方法,编写线程执行体
3. 创建线程对象,调用start()方法启动线程

```java
public class TestRunnable01 implements Runnable{    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("*******************");
        }
    }    public static void main(String[] args) {
        TestRunnable01 testRunnable01 = new TestRunnable01();
        new Thread(testRunnable01).start();
    }
}```

### 5.小结

- 继承Thread
- 子类继承Thread类具备多线程能力
- 启动线程:子类对象.start()
- 不建议使用:避免OOP单继承局限性

- 实现Runnable接口
- 实现接口Runnable具备多线程能力
- 启动线程:传入目标对象+Thread对象。start()
- 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用

![]()

**多个线程操作同一个资源问题**

```java
//多个线程操作同一个资源
//模拟买票

//发现问题:多个线程操作同一个人资源的情况下,线程不安全,数据紊乱。

public class TestRunnable02 implements Runnable{
    private  int ticket=10;
    public void run() {
        while (true){
            if (ticket<=0){
                break;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticket--+"票");        }
    }    public static void main(String[] args) {
        TestRunnable02 runnable02=new TestRunnable02();
        new Thread(runnable02,"小鹏").start();
        new Thread(runnable02,"小强").start();
        new Thread(runnable02,"小慧").start();
    }
}
```### **6.实例:龟兔赛跑**
```java
import org.omg.Messaging.SyncScopeHelper;public class Race implements Runnable{
    private static String winner;
    public void run() {
        for (int i = 0; i <= 100; i++) {            //模拟兔子睡觉
            if (Thread.currentThread().getName().equals("兔子")&&i%50==0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }            //判断100步
            if (win(i)){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
        }
    }    //判断胜利者
    public boolean win(int step){
        if (winner!=null){
            return true;
        }
        if (step>=100){
            winner=Thread.currentThread().getName();
            System.out.println("胜利者是"+winner);        }
        return false;
    }    public static void main(String[] args) {
        Race race=new Race();
        new Thread(race,"兔子").start();
        new Thread(race,"乌龟").start();
    }
}
```### 7.Callable
![]()
### 8.静态代理模式```java
//静态代理模式总结:
//真实对象和代理对象都要实现同一个接口
//代理对象要代理真实对象//好处:
//代理对象可以做很多真实对象做不了的事情
//真实对象专注做自己的事情public class StaticProxy {
    public static void main(String[] args) {
       WeCompany weCompany=new WeCompany(new You());
       weCompany.HappyMarry();    }
}interface Marry{
    void HappyMarry();
}class You implements Marry{
    public void HappyMarry() {
        System.out.println("结婚");
    }}
class WeCompany implements  Marry{
    private  Marry marry;    public WeCompany(Marry marry) {
        this.marry = marry;
    }    public void HappyMarry() {
        before();
        this.marry.HappyMarry();
        after();
    }
    public void before(){
        System.out.println("结婚之前,布置现场");
    }
    public void after(){
        System.out.println("结婚之后,收尾款");
    }
}
```### 9.Lamda表达式
1. 函数式接口:只有一个抽象方法的接口
2. 对于函数式接口,我们可以通过lambda表达式来创建该接口的对象
3. lambda推导过程代码
   ```java 
   import java.awt.peer.LabelPeer;

   /*
   推到lambda表达式
    */
   public class TestLambda {

       //3.静态内部类
       static class Like2 implements ILikeLamb{
           public void lambda() {
               System.out.println("i like lambda2***");
           }
       }

       public static void main(String[] args) {
           //方式1使用外部类
           ILikeLamb like  = new Like1();
           like.lambda();
           //方式2使用静态内部类
           like=new Like2();
           like.lambda();


           //4.局部内部类
           class Like3 implements ILikeLamb{

               public void lambda() {
                   System.out.println("i like lambda3!!!");
               }
           }

           //方式3使用局部内部类
           like=new Like3();
           like.lambda();

           //5.匿名内部类
           like=new ILikeLamb() {
               public void lambda() {
                   System.out.println("i like lambda4~~~~~~");
               }
           };
           //方式4使用匿名内部类
           like.lambda();

           //6.lambda表达式

           like=() ->  {
                   System.out.println("i like lambda5~***~~");
           };
           //方式5使用lambda表达式
           like.lambda();


       }
   }


   //1.定义一个函数式接口
   interface ILikeLamb{
       void lambda();
   }
   //2.实现类
   class Like1 implements ILikeLamb{
       public void lambda() {
           System.out.println("i like lambda");
       }
   }
   ```   **lambda简化**
```java 
 class TestLambda2 {
     public static void main(String[] args) {         //局部内部类
         class Love implements ILove{
             @Override
             public void live(int a) {
                 System.out.println("i love number is"+a);
             }
         }
         ILove love=new Love();
         love.live(666);         //匿名内部类
         love=new ILove() {
             @Override
             public void live(int a) {
                 System.out.println("i love number is"+a);
             }
         };
         love.live(888);         //lambda表达式
         love=(int a)-> {
                 System.out.println("i love number is"+a);
         };
         love.live(999);         //简化1,去参数类型
         love=(a)-> {
             System.out.println("i love number is"+a);
         };
         //简化2.去括号
         love=a-> {
             System.out.println("i love number is"+a);
         };
         //简化3.去花括号
         love = a -> System.out.println("i love number is"+a);         //总结:
            //方法中只有一行代码才可以简化花括号,多行得用{};
            //前提接口必须是函数式接口;
            //多个参数得同时都去掉类型,却得用()括起来(a,b,c);         }
     }
interface ILove{
    public void live(int a);
}```
### 10.线程状态
**五种状态**
![在这里插入图片描述]()
两张图对比**理解**
 
![在这里插入图片描述]()
### **11.线程方法**
![在这里插入图片描述]()
 
### 12.线程停止
![在这里插入图片描述]()
自定义停止代码
```java 
public class ThreadStop implements Runnable{    private boolean flg=true;
    @Override
    public void run() {
        int i=0;
        while (flg){
            System.out.println("running**********"+i++);
        }
    }    public static void main(String[] args) {
        ThreadStop threadStop=new ThreadStop();
        new Thread(threadStop).start();        for (int i = 0; i < 500; i++) {
            System.out.println("main线程"+i);
            if (i==444){
                threadStop.stop();
                System.out.println("该线程停止了***************");
            }
        } 
    }
    public void stop(){
        this.flg=false;
    }
}```
 
### 13.线程休眠
![在这里插入图片描述]()
**模拟倒计时**
```java
//模拟倒计时
public class ThreadSleep2 implements Runnable{
    private  int ticket=10;
    @Override
    public void run() {
        while (true){
            if (ticket <= 0) {
                break;
            }
            //模拟延时            try {
                Thread.sleep(1000);
                System.out.println(ticket--);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }    }
    public static void main(String[] args) {
        ThreadSleep2 threadSleep2=new ThreadSleep2();
        new Thread(threadSleep2).start();
    }
}```
 
**模拟时钟**
```java
import java.text.SimpleDateFormat;
import java.util.Date;//模拟时钟
import static java.lang.System.currentTimeMillis;public class ThreadSleep3 {
    public static void main(String[] args) {
        //获取当前系统时间
        Date time= new Date(System.currentTimeMillis());        while (true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(time));
                time= new Date(System.currentTimeMillis());//更新时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}```
### 14.线程礼让
- 礼让线程,让当前正在执行的线程暂停,但步阻塞
- 将线程从运行状态转为就绪状态
- 让CPU重新调度,礼让不一定成功!看CPU心情```java
//礼让不一定成功
public class ThreadYield {    public static void main(String[] args) {
        MyYield myYield=new MyYield();        new Thread(myYield,"aaa").start();
        new Thread(myYield,"bbb").start();
    }}
class MyYield implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"开始执行");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"停止执行");
    }
}
```### 15.Join
- Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞
- 可以想象成插队```java 
//测试join//类似于插队
public class ThreadJoin implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"来了"+i);
        }
    }    public static void main(String[] args) {
        ThreadJoin threadJoin = new ThreadJoin();
        Thread thread=new Thread(threadJoin,"vip");
        thread.start();        for (int i = 0; i < 100; i++) {
            if (i==40){
                try {
                    thread.join();//强势插入,主线程阻塞
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("main来了"+i);
        }    }
}
```
### 16.线程状态观测
- ```
  Thread.State
  ```- 线程可以处于以下状态之一:
  - [`NEW`](../../java/lang/Thread.State.html#NEW)  
    尚未启动的线程处于此状态。 
  - [`RUNNABLE`](../../java/lang/Thread.State.html#RUNNABLE)  
    在Java虚拟机中执行的线程处于此状态。 
  - [`BLOCKED`](../../java/lang/Thread.State.html#BLOCKED)  
    被阻塞等待监视器锁定的线程处于此状态。 
  - [`WAITING`](../../java/lang/Thread.State.html#WAITING)  
    正在等待另一个线程执行特定动作的线程处于此状态。 
  - [`TIMED_WAITING`](../../java/lang/Thread.State.html#TIMED_WAITING)  
    正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。 
  - [`TERMINATED`](../../java/lang/Thread.State.html#TERMINATED)  
    已退出的线程处于此状态。 ### 17.线程的优先级
set和get--priority()
低优先级只意味着调度概率低,并不是优先级低就不会被先调用。
测试代码
```java 
public class ThreadPriority {
    public static void main(String[] args) {        System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
        MyThread myThread=new MyThread();
        Thread thread1=new Thread(myThread);
        Thread thread2=new Thread(myThread);
        Thread thread3=new Thread(myThread);
        Thread thread4=new Thread(myThread);
        Thread thread5=new Thread(myThread);        //设置优先级
        thread1.setPriority(6);
        thread1.start();        thread2.setPriority(2);
        thread2.start();        thread3.setPriority(8);
        thread3.start();        thread4.setPriority(4);
        thread4.start();        thread5.setPriority(10);
        thread5.start();    }
}class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
    }
}
```### 18.守护(daemon)线程
- 线程分为用户线程和守护线程
- 虚拟机必须确保用户线程执行完毕
- 虚拟机不用等待守护线程执行完毕
- 如,后台记录操作日志,监控内存,垃圾回收等
 
```java
public class ThreadDaemon {
    public static void main(String[] args) {
        Gad gad=new Gad();
        Our our=new Our();        Thread t=new Thread(gad);
        Thread t1=new Thread(our);

        t.setDaemon(true);//用户线程默认false
        t.start();

        t1.start();
    } 
}
class Gad implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println("Gad NB alone living");
        }
    }
}class Our implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("living*********living"+i);
        }
        System.out.println("death---------death=-");
    }
}


```

### 19.线程同步

1. 多个线程操作同一个资源

2. 并发:同一个对象被多个线程同时操作

3. 处理多线程问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象。这时候我们就需要线程同步,线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面的线程使用完毕,下一个线程在再使用

4. 队列+锁:锁机制(synchronized)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zJT2Wokt-1603259602918)(C:\Users\Wv587-h\AppData\Roaming\Typora\typora-user-images\image-20201020163000351.png)]

**性能倒置**

### 20.三大线程不安全列子

1. 购票;

```java
   package safe;

   public class UnSafeTicket {
       public static void main(String[] args) {
           BuyTicket buy=new BuyTicket();
           new Thread(buy,"小张").start();
           new Thread(buy,"小五").start();
           new Thread(buy,"小六").start();
           new Thread(buy,"小巴").start();
       }


   }
   class BuyTicket implements Runnable{

       private int tickets=100;
       private boolean flag=true;


       @Override
       public void run() {
           while (flag){
               try {
                   buy();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }

       }

       private void buy() throws InterruptedException {
           if (tickets<=0){
               flag=false;
               return;
           }
           Thread.sleep(100);
           System.out.println(Thread.currentThread().getName()+"拿到第"+tickets--+"票");
       }
   }


```

2. 取款;

```java
   package safe;

   import com.sun.org.apache.bcel.internal.generic.NEW;

   import javax.naming.Name;

   public class UnSafeBank {

       public static void main(String[] args) {
           Account account= new Account("联邦",9999999);
           Bank bank=new Bank(account,5111111);
           Bank bank2=new Bank(account,5111111);

           Thread t=new Thread(bank,"多多");
           t.start();

           Thread t2=new Thread(bank2,"零零");
           t2.start();
       }





   }
   class Account{

       private String account;
       private int money;

       public Account(String account, int money) {
           this.account = account;
           this.money = money;
       }

       public String getAccount() {
           return account;
       }

       public void setAccount(String account) {
           this.account = account;
       }

       public int getMoney() {
           return money;
       }

       public void setMoney(int money) {
           this.money = money;
       }
   }

   class Bank implements Runnable{
       Account account;
       int drawMoney;
       int nowMoney;

       public Bank(Account account, int drawMoney) {

           this.account = account;
           this.drawMoney = drawMoney;

       }


       @Override
       public void run() {
           if (account.getMoney()-drawMoney<0){
               System.out.println("余额不足!!!");
               return;
           }
           try {
               Thread.sleep(1000);//等待让两个线程都进来
           } catch (InterruptedException e) {
               e.printStackTrace();
           }

           account.setMoney(account.getMoney()-drawMoney);

           nowMoney=nowMoney+drawMoney;

           System.out.println(Thread.currentThread().getName()+"取走了"+nowMoney);
           System.out.println(account.getAccount()+"卡上余额为:"+account.getMoney());

       }
   }


```

3. 集合list;

```java
   package safe;

   import java.util.ArrayList;
   import java.util.List;

   public class UnsafeList {
       public static void main(String[] args) throws InterruptedException {
           List<String> list=new ArrayList<String>();
           for (int i = 0; i < 10010; i++) {
               new Thread(()->{
                   list.add(Thread.currentThread().getName());
               }).start();
           }
           Thread.sleep(1000);
           System.out.println(list.size());
       }

   }

   ``` 
### 21.synchronized
- 同步方法
  ```java
  package safe;

  public class SafeTicket {
      public static void main(String[] args) {
          BuyTicket1 buy=new BuyTicket1();
          new Thread(buy,"小张").start();
          new Thread(buy,"小五").start();
          new Thread(buy,"小六").start();
          new Thread(buy,"小巴").start();
      }


  }
  class BuyTicket1 implements Runnable{

      private int tickets=100;
      private boolean flag=true;


      @Override
      public void run() {
          while (flag){
              try {
                  buy();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }

      }
  //在方法加synchronized
      private synchronized void buy() throws InterruptedException {
          if (tickets<=0){
              flag=false;
              return;
          }
          Thread.sleep(100);
          System.out.println(Thread.currentThread().getName()+"拿到第"+tickets--+"票");
      }
  }

  ``` 
- 同步块
  ```java
  package safe;

  public class SafeBank {

      public static void main(String[] args) {
          Account1 account= new Account1("联邦",9999999);
          Bank1 bank=new Bank1(account,5111111);
          Bank1 bank2=new Bank1(account,5111111);

          Thread t=new Thread(bank,"多多");
          t.start();

          Thread t2=new Thread(bank2,"零零");
          t2.start();
      }





  }
  class Account1{

      private String account;
      private int money;

      public Account1(String account, int money) {
          this.account = account;
          this.money = money;
      }

      public String getAccount() {
          return account;
      }

      public void setAccount(String account) {
          this.account = account;
      }

      public int getMoney() {
          return money;
      }

      public void setMoney(int money) {
          this.money = money;
      }
  }

  class Bank1 implements Runnable{
      Account1 account;
      int drawMoney;
      int nowMoney;



      public Bank1(Account1 account, int drawMoney) {

          this.account = account;
          this.drawMoney = drawMoney;

      }


      @Override
      public void run() {
          //同步块,锁 变化的对象
          synchronized(account){   //锁的对象就是变化的量,需要增删改
              if (account.getMoney()-drawMoney<0){
                  System.out.println("余额不足!!!");
                  return;
              }
              try {
                  Thread.sleep(1000);//等待让两个线程都进来
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }

              account.setMoney(account.getMoney()-drawMoney);

              nowMoney=nowMoney+drawMoney;

              System.out.println(Thread.currentThread().getName()+"取走了"+nowMoney);
              System.out.println(account.getAccount()+"卡上余额为:"+account.getMoney());

          }

          }

  }
  ```- 对比JUC
  ```java
  package safe;

  import java.util.concurrent.CopyOnWriteArrayList;

  //测试JUC安全类型的集合
  public class TestJUC {
      public static void main(String[] args) throws InterruptedException {
          CopyOnWriteArrayList<String> co=new CopyOnWriteArrayList<String>();
          for (int i = 0; i < 1000; i++) {
              new Thread(()->{
                  co.add(Thread.currentThread().getName());
              }).start();
          }
          Thread.sleep(2000);
          System.out.println(co.size());
      }
  }



```

 

### 22.死锁

- 多个线程各自占有一些资源,并且互相等待其他线程占有的资源才能运行,而导致两个过着多个线程都在等待对方释放资源,都停止执行的情况

```java
package thread;

//多个资源互相抱着对方的资源,形成僵持

public class DeadLock {
    public static void main(String[] args) {
        Makeup makeup=new Makeup(0,"小红");
        Makeup makeup1=new Makeup(1,"大蓝");        makeup.start();
        makeup1.start();    }
}class Lipstick{
}
class Mirror{
}
class Makeup extends Thread{
    //static确保资源唯一
    static private Lipstick lipstick=new Lipstick();
    static private Mirror mirror=new Mirror();    int choose;
    String name;    public Makeup(int choose, String name) {
        this.choose = choose;
        this.name = name;
    }    public void run(){
        try {
            makeup();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }    private void makeup() throws InterruptedException {
        if (choose==0){
            synchronized (lipstick){
                System.out.println(this.name+"拿到口红!!");
                Thread.sleep(1000);
                synchronized (mirror){
                    System.out.println(this.name+"拿到镜子!!!");
                }            }
            /*synchronized (mirror){
                System.out.println(this.name+"拿到镜子!!!");
            }*/        }else {
            synchronized (mirror){
                System.out.println(this.name+"拿到镜子!!");
                Thread.sleep(2000);
                synchronized (lipstick){
                    System.out.println(this.name+"拿到口红!!!");
                }
            }
           /* synchronized (lipstick){
                System.out.println(this.name+"拿到口红!!!");
            }*/
        }
    }
}


```

- 产生死锁的四个必要条件
- 互斥条件:一个资源每次只能被一个进程使用。
- 请求与保持条件:一个进程因请求资源而阻塞是,对已获得的资源保持不放。
- 不剥夺条件:进程以获得的资源,在未使用完之前,不能强行剥夺。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

> 上面列出的四个条件,只要想办法破其中的任意一个或多个就可以避免死锁发生

### 23.Lock

1. 从JDK5.0开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当

2. java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。

3. 锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象

4. ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁。

> **Lock的使用**

![在这里插入图片描述]()

> 测试代码

```java
package safe;import java.util.concurrent.locks.ReentrantLock;
public class TestLock {
    public static void main(String[] args) {
        TicketLock ti=new TicketLock();
        new Thread(ti).start();
        new Thread(ti).start();
        new Thread(ti).start();
    }}
class TicketLock implements Runnable{
    int ticket=10;
    private final ReentrantLock lock=new ReentrantLock();//创建锁对象
    @Override
    public void run() {
        while (true) {            try {
                lock.lock();//加锁
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(ticket--);                } else {
                    return;                }
            } finally {
                lock.unlock();//解锁
            }        }
    }
}

```

 

> **synchronized与Lock的对比**

- Lock是显式锁(手动开启和关闭锁,别忘记关闭锁) synchronized是隐式锁,出了作用域自动释放

- Lock只有代码块锁,synchronized有代码块锁和方法锁

- 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)

- 优先使用顺序:
- Lock >同步代码块(已经进入了方法体,分配了相应资源)>同步方法(在方法体之外)

### 24.生产者消费者

> 代码

```java
package safe;import java.util.LinkedList;
public class TestPC {
    //最大容量
    public static final int MAX_SIZE = 10;
    //存储媒介
    public static LinkedList<Integer> list = new LinkedList<>();    class Producer implements Runnable {
        @Override
        public void run() {
            synchronized (list) {
                //仓库容量已经达到最大值
                while (list.size() == MAX_SIZE) {
                    System.out.println("仓库已满,生产者" + Thread.currentThread().getName() + "不可生产.");
                    try {
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                list.add(1);
                System.out.println("生产者" + Thread.currentThread().getName() + "生产, 仓库容量为" + list.size());
                list.notify();
            }
        }
    }    class Consumer implements Runnable {
        @Override
        public void run() {
            synchronized (list) {
                while (list.size() == 0) {
                    System.out.println("仓库为空,消费者" + Thread.currentThread().getName() + "不可消费.");
                    try {
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                list.removeFirst();
                System.out.println("消费者" + Thread.currentThread().getName() + "消费,仓库容量为" + list.size());
                list.notify();
            }
        }
    }    public static void main(String[] args) {
        TestPC pc = new TestPC();
        Producer producer = pc.new Producer();
        Consumer consumer = pc.new Consumer();        for (int i = 0; i < 10; i++) {
            Thread pro = new Thread(producer,"P");
            pro.start();
            Thread con = new Thread(consumer,"C");
            con.start();
        }
    }}

```

### 25.线程池

> 使用线程池

![在这里插入图片描述]()

> 代码

```java
package thread;import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPool {
    public static void main(String[] args) {
        //创建服务,创建线程池,newFixedThreadPool,参数:个数
        ExecutorService service= Executors.newFixedThreadPool(5);        service.execute(new MyThread1());
        service.execute(new MyThread1());
        service.execute(new MyThread1());
        service.execute(new MyThread1());
        service.execute(new MyThread1());        //关闭服务
        service.shutdown();
    }
}class MyThread1 implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

```

 

### 26.总结

> 三种方法

```JAVA
package thread;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;public class ThreadNew {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //1
        Thread1 t1=new Thread1();
        t1.start();        //2.
        Thread2 t2=new Thread2();
        new Thread(t2).start();        FutureTask<Integer> task=new FutureTask<Integer>(new Thread3());
        new Thread(task).start();
        Integer integer=task.get();
        System.out.println(integer);
    }
}//1.继承Thread
class Thread1 extends Thread{
    public void run(){
        System.out.println("Thread111");
    }
}
//2.实现Runnable
class Thread2 implements Runnable{
    @Override
    public void run() {
        System.out.println("thread222");
    }
}//3.实现Callable
class Thread3 implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("thread3333");
        return 100;
    }
}
```