当前位置:首页 » 《随便一记》 » 正文

一文学会多线程_m0_60264772的博客

26 人参与  2022年03月29日 17:06  分类 : 《随便一记》  评论

点击全文阅读


线程和进程的概念

程序:是为完成特定任务,用某种语言编写的一组指令的集合。即一段静态的代码,静态对象。

进程:指在运行中的程序,程序一旦运行就是进程,同时进程也是是线程的容器,是系统进行资源分配和调度的单元,系统会在运行时为每个进程分配不同的内存取余,是资源分配的最小单元。是一个动态的过程:有它自身的产生,存在和消亡的过程。--生命周期

线程(thread)是操作系统能够进行运算调度和执行的最小单元。它被包含在进程之中,是进程中的实际运作单位,一条线程指的是进程中一个单一顺序的控制流,是一个程序内部的一条执行路径,一个进程中可以并发多个线程,每条线程可以执行不同的任务。线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc)

多线程的创建

继承Thread类

 /**
  * 创建多线程的方式一:
  * 1.继承Thread类
  * 2.重写Thread类中的run()方法
  * 3.创建Thread类子类的对象
  * 4.通过此对象调用start()
  * 例子:遍历100000以内的所有偶数
  */
 public class ThreadTest {
     public static void main(String[] args) {
         MyThread m1 = new MyThread();
 ​
         m1.start();
 ​
         for (int i = 0; i < 100000; i++) {
             if(i%2 == 0){
                 System.out.println(i+"main");
             }
         }
     }
 ​
 }
 class MyThread extends Thread{
     @Override
     public void run() {
         for (int i = 0; i <100000 ; i++) {
             if(i%2 == 0){
                 System.out.println(i);
             }
         }
     }
 }

会发现执行结果是相交的

 ……
 27250main
 27252main
 81768
 81770
 ……
 /**
  * 练习
  * 创建俩个多线程,分别打印100以内的奇数和偶数
  */
 public class ThreadTest {
     public static void main(String[] args) {
         MyThread1 m1 = new MyThread1();
         MyThread2 m2 = new MyThread2();
         m1.start();
         m2.start();
     }
 }
 class MyThread1 extends Thread{
     @Override
     public void run() {
         for (int i = 0; i <100 ; i++) {
             if(i%2 == 0){
                 System.out.println(Thread.currentThread().getName()+": "+i);
             }
         }
     }
 }
 class MyThread2 extends Thread{
     @Override
     public void run() {
         for (int i = 0; i <100 ; i++) {
             if(i%2 == 1){
                 System.out.println(Thread.currentThread().getName()+": "+i);
             }
         }
     }
 }

运行结果

 Thread-0: 0
 Thread-1: 1
 Thread-0: 2
 Thread-1: 3
 Thread-0: 4
 Thread-1: 5
 Thread-0: 6
 Thread-1: 7
 Thread-0: 8
 Thread-1: 9
 Thread-0: 10
 Thread-1: 11
 Thread-0: 12
 Thread-1: 13
 Thread-0: 14
 Thread-1: 15
 ……

实现Runnable接口

 /**
  * 创建多线程的方式二:
  * 1.创建一个实现了Runnable接口的类
  * 2.实现类去实现Runnable接口中的抽象方法:run()
  * 3.创建实现类的对象
  * 4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
  * 5.通过Thread类的对象调用start()
  */
 public class RunnableTest {
     public static void main(String[] args) {
         Run run=new Run();
         Thread thread1 = new Thread(run);
         Thread thread2 = new Thread(run);
         thread1.start();
         thread2.start();
     }
 }
 class Run implements Runnable{
     @Override
     public void run() {
         for (int i = 0; i < 100000; i++) {
             System.out.println(Thread.currentThread().getName()+"  "+i);
         }
     }
 }
 //Thread類源码 
 public class Thread implements Runnable {
     private Runnable target;
    
    public Thread(Runnable target) {
         this((ThreadGroup)null, target, "Thread-" + nextThreadNum(), 0L);
     }
    public void run() {
         if (this.target != null) {
             this.target.run();
         }
    }
 ​

多线程实现窗口卖票的两种方式

 public class WindowsTest {
     public static void main(String[] args) {
         Windows windows1 = new Windows();
         Windows windows2 = new Windows();
         Windows windows3 = new Windows();
         windows1.setName("窗口1");
         windows2.setName("窗口3");
         windows3.setName("窗口2");
         windows1.start();
         windows2.start();
         windows3.start();
     }
 }
 class Windows extends Thread{
 ​
     private static int ticket = 100;//注意static
 ​
     @Override
     public void run() {
         while(true){
             if(ticket>0){
                 System.out.println(Thread.currentThread().getName()+"卖票"+ticket);
                 ticket--;
             } else {
                 break;
             }
         }
     }
 ​
 }

 public class RunnableTest {
     public static void main(String[] args) {
         Run run=new Run();
         Thread thread1 = new Thread(run);
         Thread thread2 = new Thread(run);
         Thread thread3 = new Thread(run);
         thread1.start();
         thread2.start();
         thread3.start();
     }
 }
 class Run implements Runnable{
     private int ticket=100;//这里不用加static
     @Override
     public void run() {
         while(true){
             if(ticket>0){
                 System.out.println(Thread.currentThread().getName()+"卖票"+ticket);
                 ticket--;
             }else {
                 break;
             }
         }
     }
 }

多线程创建两种方式的比较

开发中:优先选择实现Runnable接口的方式

  1. 实现的方式没有单继承的局限性

  2. 实现的方式更适合来处理多个线程共享数据

联系:Thread继承了Runnable接口

相同点:都需要重写run方法,将线程执行的逻辑写在run方法中

JDK5.0新增线程创建方式

实现Callable接口

  • 相比Runnable,可以有返回值

  • 方法可以抛出异常

  • 支持泛型的返回值

  • 需要借助FutureTask类,比如获取返回结果

创建线程的方式三:

  1. 创建一个实现callable的接口

  2. 实现call方法,将此线程需要执行的操作声明在call()中

  3. 创建callable接口实现类的对象

  4. 将此callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象

  5. 将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象并调用start方法

  6. 获取callable中call方法的返回值

 public class CallableTest {
 ​
     public static void main(String[] args) {
         ThreadTests t = new ThreadTests();
         FutureTask futureTask1 = new FutureTask(t);
         new Thread(futureTask1).start();
         try {
             Object sum = futureTask1.get();
             System.out.println("总合"+sum);
         }catch (Exception e){
             e.printStackTrace();
         }
     }
 }
 ​
 class ThreadTests implements Callable{
     @Override
     public Object call() throws Exception {
       int num=0;
         for (int i = 0; i <= 100; i++) {
             if (i % 2 == 0){
                 System.out.println(i);
                 num += i;
             }
         }
             return num;
     }
 }

线程池创建线程

优点:

  • 提高响应速度(减少了创建新线程的时间)

  • 降低资源消耗(重复利用线程池中线程,不需要每次都创建)

  • 便于线程管理

 public class ThreadPool {
     public static void main(String[] args) {
         ExecutorService service = Executors.newFixedThreadPool(10);
         service.execute(new NumberThreadTest());//适合Runnable接口
         service.execute(new NumberThreadTest());
         //service.submit()适合使用和callable
         service.shutdown();//关闭线程池
     }
 }
 class NumberThreadTest implements Runnable{
     private static int ticket=100;
     @Override
     public void run() {
         while(true){
             if (ticket>0){
                 System.out.println(Thread.currentThread().getName()+":"+ticket);
                 ticket--;
             }else {
                 break;
             }
         }
     }
 }

线程常用方法

 yield();//释放当前cpu的执行权

 join();//在线程a中调用线程b的join方法,线程a会陷入阻塞状态直到线程b执行完毕
 stop();//强制线程生命期结束,不推荐使用
 boolean isAlive();//判断线程是否还或者
 sleep(long timemilltime);//让当前线程睡眠指定的milltime毫秒,在指定的milltime毫秒时间内,当前线程是阻塞状态

以下三个方法必须在同步代码块或者同步方法中使用,并且调用者必须是同步代码块或同步方法中的同步监视器(同一把锁)否则会出现IllegalMonitorStateException异常

属于Object类中的方法

 wait():一旦执行此方法,当前线程进入阻塞状态,并释放同步监视器
 notify():一旦执行此方法,就会唤醒被wait的一个线程,如果有多个线程被wait,则唤醒优先级高的
 notifyAll():唤醒所有线程

线程的优先级

 MAX_PRIORITY:10
 MIN_PRIORITY:1
 NORM_PRIORITY:5

默认优先级都为5

 如何获取:
 1. getPriority():获取线程的优先级
 2. setPriority(int p):设置线程的优先级

并不是优先级高就一定先被CPU执行,只能从概率上讲更容易被CPU执行

线程的生命周期

  1. 新建

  2. 就绪

  3. 运行

  4. 阻塞

  5. 死亡

synchronized

操作共享数据的代码,即为需要被同步的代码

  • 共享数据:多个线程共同操作的变量

  • 同步监视器:锁

  • 任何一个类的对象都可以充当锁

  • 多个线程必须用同一把锁

synchronized同步代码块解决线程安全问题

Runnable同步代码块解决线程安全的问题

 /**
  * 操作共享数据的代码,即为需要被同步的代码
  * 共享数据:多个线程共同操作的变量
  * 同步监视器:锁
  * 任何一个类的对象都可以充当锁
  * 多个线程必须用同一把锁
  */
 public class RunnableTest {
     public static void main(String[] args) {
         Run run=new Run();
         Thread thread1 = new Thread(run);
         Thread thread2 = new Thread(run);
         Thread thread3 = new Thread(run);
         thread1.start();
         thread2.start();
         thread3.start();
     }
 }
 class Run implements Runnable{
     private  int ticket=100;
     Object object=new Object();
     @Override
     public void run() {
 ​
         while(true){
             synchronized(object){//可以使用this充当锁,this为当前对象
                 if(ticket>0){
                     try {
                         Thread.sleep(200);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     System.out.println(Thread.currentThread().getName()+"卖票"+ticket);
                     ticket--;
                 }else {
                     break;
                 }
             }
         }
     }
 }

执行结果

 Thread-0卖票100
 Thread-0卖票99
 Thread-2卖票98
 Thread-1卖票97
 Thread-1卖票96
 Thread-1卖票95
 Thread-2卖票94
 Thread-2卖票93
 Thread-2卖票92
 Thread-2卖票91
 Thread-2卖票90
 Thread-2卖票89
 Thread-2卖票88
 Thread-2卖票87
 Thread-2卖票86
 Thread-2卖票85
 Thread-0卖票84
 Thread-0卖票83
 Thread-0卖票82
 Thread-0卖票81
 Thread-0卖票80
 Thread-0卖票79
 Thread-0卖票78
 Thread-0卖票77
 Thread-0卖票76
 Thread-0卖票75
 Thread-0卖票74
 Thread-0卖票73
 Thread-0卖票72
 Thread-0卖票71
 Thread-0卖票70
 Thread-0卖票69
 Thread-0卖票68
 Thread-0卖票67
 Thread-0卖票66
 Thread-0卖票65
 Thread-0卖票64
 Thread-0卖票63
 Thread-0卖票62
 Thread-0卖票61
 Thread-0卖票60
 Thread-2卖票59
 Thread-2卖票58
 Thread-2卖票57
 Thread-2卖票56
 Thread-2卖票55
 Thread-2卖票54
 Thread-2卖票53
 Thread-2卖票52
 Thread-2卖票51
 Thread-2卖票50
 Thread-2卖票49
 Thread-2卖票48
 Thread-2卖票47
 Thread-2卖票46
 Thread-2卖票45
 Thread-2卖票44
 Thread-2卖票43
 Thread-1卖票42
 Thread-1卖票41
 Thread-1卖票40
 Thread-1卖票39
 Thread-1卖票38
 Thread-1卖票37
 Thread-1卖票36
 Thread-1卖票35
 Thread-1卖票34
 Thread-1卖票33
 Thread-1卖票32
 Thread-1卖票31
 Thread-1卖票30
 Thread-1卖票29
 Thread-1卖票28
 Thread-1卖票27
 Thread-1卖票26
 Thread-2卖票25
 Thread-2卖票24
 Thread-2卖票23
 Thread-2卖票22
 Thread-2卖票21
 Thread-2卖票20
 Thread-2卖票19
 Thread-2卖票18
 Thread-2卖票17
 Thread-2卖票16
 Thread-2卖票15
 Thread-2卖票14
 Thread-2卖票13
 Thread-2卖票12
 Thread-2卖票11
 Thread-2卖票10
 Thread-2卖票9
 Thread-2卖票8
 Thread-2卖票7
 Thread-2卖票6
 Thread-2卖票5
 Thread-2卖票4
 Thread-2卖票3
 Thread-0卖票2
 Thread-0卖票1
 ​
 Process finished with exit code 0

同步的方式解决了线程安全的问题,操作同步代码时,只有一个线程参与,其他线程等待,相当于一个单线程的过程,效率低

Thread方式同步代码块解决线程安全的问题

 public class ThreadTest {
     public static void main(String[] args) {
         MyThread m1 = new MyThread();
         MyThread m2 = new MyThread();
         MyThread m3 = new MyThread();
         m1.start();
         m2.start();
         m3.start();
     }
 }
 class MyThread extends Thread{
     private static int ticket=100;
     Object object=new Object();
     @Override
     public void run() {
         while(true){
             synchronized(object){//不可以使用this充当锁,这里this代表了m1,m2,m3三个对象
                 try {
                     sleep(10);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
                 if(ticket > 0){
                     System.out.println(Thread.currentThread().getName()+"卖票:"+ticket);
                     ticket--;
                 }else {
                     break;
                 }
             }
 ​
         }
     }
 }

执行结果

 Thread-0卖票:100
 Thread-1卖票:100
 Thread-2卖票:100
 Thread-2卖票:97
 Thread-1卖票:97
 Thread-0卖票:97
 Thread-2卖票:94
 Thread-0卖票:94
 Thread-1卖票:94
 Thread-1卖票:91
 Thread-2卖票:91
 Thread-0卖票:90
 Thread-2卖票:88
 Thread-1卖票:88
 Thread-0卖票:88
 Thread-2卖票:85
 Thread-0卖票:84
 Thread-1卖票:84
 Thread-2卖票:82
 Thread-0卖票:82
 Thread-1卖票:82
 Thread-2卖票:79
 Thread-0卖票:79
 Thread-1卖票:78
 Thread-2卖票:76
 Thread-1卖票:76
 Thread-0卖票:76
 Thread-2卖票:73
 Thread-1卖票:73
 Thread-0卖票:73
 Thread-0卖票:70
 Thread-1卖票:70
 Thread-2卖票:70
 Thread-1卖票:67
 Thread-0卖票:67
 Thread-2卖票:66
 Thread-2卖票:64
 Thread-1卖票:64
 Thread-0卖票:62
 Thread-2卖票:61
 Thread-1卖票:61
 Thread-0卖票:61
 Thread-1卖票:58
 Thread-0卖票:58
 Thread-2卖票:56
 Thread-0卖票:55
 Thread-1卖票:55
 Thread-2卖票:55
 Thread-0卖票:52
 Thread-1卖票:52
 Thread-2卖票:52
 Thread-1卖票:49
 Thread-2卖票:49
 Thread-0卖票:49
 Thread-2卖票:46
 Thread-0卖票:46
 Thread-1卖票:46
 Thread-2卖票:43
 Thread-0卖票:43
 Thread-1卖票:43
 Thread-2卖票:40
 Thread-1卖票:40
 Thread-0卖票:40
 Thread-0卖票:37
 Thread-2卖票:37
 Thread-1卖票:37
 Thread-2卖票:34
 Thread-1卖票:34
 Thread-0卖票:34
 Thread-2卖票:31
 Thread-0卖票:31
 Thread-1卖票:31
 Thread-1卖票:28
 Thread-2卖票:28
 Thread-0卖票:28
 Thread-0卖票:25
 Thread-2卖票:25
 Thread-1卖票:25
 Thread-1卖票:22
 Thread-0卖票:22
 Thread-2卖票:22
 Thread-2卖票:19
 Thread-0卖票:19
 Thread-1卖票:19
 Thread-2卖票:16
 Thread-1卖票:16
 Thread-0卖票:16
 Thread-2卖票:13
 Thread-0卖票:13
 Thread-1卖票:13
 Thread-2卖票:10
 Thread-0卖票:10
 Thread-1卖票:10
 Thread-2卖票:7
 Thread-0卖票:7
 Thread-1卖票:7
 Thread-2卖票:4
 Thread-1卖票:4
 Thread-0卖票:4
 Thread-1卖票:1
 Thread-2卖票:1
 Thread-0卖票:1
 ​
 Process finished with exit code 0
 ​

会发现还是线程不安全,这是因为三个对象使用的锁不是同一把锁了

一定要注意给object 加上static 才行

 static Object object=new Object();

加入后就会发现线程又安全了

 或者使用 MyThread.class 充当锁

Synchronized同步方法解决线程安全问题

使用同步方法解决线程安全问题

实现Runnable接口方式

 public class SynchronizedMethod {
     public static void main(String[] args) {
         ThreadMethod threadMethod = new ThreadMethod();
         Thread thread1 = new Thread(threadMethod);
         Thread thread2 = new Thread(threadMethod);
         Thread thread3 = new Thread(threadMethod);
         thread1.start();
         thread2.start();
         thread3.start();
     }
 }
 class ThreadMethod implements Runnable{
     private  int ticket=100;
     public synchronized void show(){//这里用的锁是this
         try {
             Thread.sleep(10);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         if(ticket > 0){
             System.out.println(Thread.currentThread().getName()+"卖票:"+ticket);
             ticket--;
         }
     }
 ​
     @Override
     public void run() {
         while(ticket>0){
             show();
         }
     }
 }

继承Thread类方式

 public class SynchronizedMethodThread {
     public static void main(String[] args) {
         ThreadMethod threadMethod1 = new ThreadMethod();
         ThreadMethod threadMethod2 = new ThreadMethod();
         ThreadMethod threadMethod3 = new ThreadMethod();
         threadMethod1.start();
         threadMethod2.start();
         threadMethod3.start();
     }
 }
 class ThreadMethod extends Thread{
     private  static int ticket=100;
 ​
     public static synchronized void show(){//这里必须加上static,不加上static锁使用的为this对象,这里创建了三个对象。加上static锁使用的为ThreadMethod.class
         try {
             Thread.sleep(10);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         if(ticket > 0){
             System.out.println(Thread.currentThread().getName()+"卖票:"+ticket);
             ticket--;
         }
     }
     @Override
     public void run() {
         while(ticket>0){
             show();
         }
     }
 }

同步方法总结

  • 同步方法仍涉及到同步监视器,只是不需要我们显示的声明

  • 非静态的同步方法,同步监视器(锁)是:this

  • 静态的同步方法,同步监视器(锁)是:当前类本身

锁方式解决线程安全问题

 public class ReentrantLockTest {
     public static void main(String[] args) {
         Window window = new Window();
         Thread thread1 = new Thread(window);
         Thread thread2 = new Thread(window);
         Thread thread3 = new Thread(window);
         thread1.start();
         thread2.start();
         thread3.start();
     }
 }
 ​
 class Window implements Runnable{
     private  int ticket=100;
     private ReentrantLock reentrantLock=new ReentrantLock();
     @Override
     public void run() {
         while (true){
             reentrantLock.lock();//加锁
             try {
                 if(ticket>0){
                     try {
                         Thread.sleep(50);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     System.out.println(Thread.currentThread().getName()+"卖票"+ticket);
                     ticket--;
                 }else {
                     break;
                 }
             }finally {
              reentrantLock.unlock();//释放锁
             }
         }
     }
 }

注意:如果用继承Thread类的方式去使用lock

必须在 锁前面加上static

 private static ReentrantLock reentrantLock=new ReentrantLock();

Synchronized和锁(Lock)方式的异同?

  • 相同:两者都可以解决线程安全问题

  • 不同:Synchronized机制在执行完相应的同步代码后,自动释放同步监视器,Lock需要手动启动同步(Lock()),同时结束也需要手动结束同步(unlock())

单例模式线程安全

 class Bank{
     private static Bank instance = null;
     private Bank(){}
     public  static  Bank  getInstance(){
 //        synchronized(Bank.class){//方式一:效率稍差
 //            if (instance == null){
 //                instance=new Bank();
 //            }
 //            return instance;
 //        }
         //方式二:效率更高
         if (instance == null){
             synchronized(Bank.class){
                 if (instance == null){
                     instance=new Bank();
                 }
             }
         }
         return instance;
     }
 }

死锁

不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁

死锁案例

 public class DeadLock {
     public static void main(String[] args) {
         StringBuffer s1=new StringBuffer();
         StringBuffer s2=new StringBuffer();
         new Thread(){
             @Override
             public void run() {
                 synchronized (s1){
                     s1.append("a");
                     s2.append("1");
                     try {
                         Thread.sleep(100);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     synchronized (s2){
                         s1.append("b");
                         s2.append("2");
                         System.out.println(s1);
                         System.out.println(s2);
                     }
                 }
             }
         }.start();
 ​
         new Thread(new Runnable() {
             @Override
             public void run() {
                 synchronized (s2){
                     s1.append("c");
                     s2.append("3");
                     try {
                         Thread.sleep(100);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     synchronized (s1){
                         s1.append("d");
                         s2.append("4");
                         System.out.println(s1);
                         System.out.println(s2);
                     }
                 }
             }
         }).start();
     }
 }

多线程通信列题

 public class CommunicationTest {
     /**
      * 实现两个线程交替打印1-100
      */
     public static void main(String[] args) {
         Test test = new Test();
         Thread t1 = new Thread(test);
         Thread t2 = new Thread(test);
         Thread t3 = new Thread(test);
         t1.start();
         t2.start();
         t3.start();
     }
 }
 class Test implements Runnable{
     private int number=1;
     @Override
     public void run() {
             while (true){//while条件不能用number <= 100 因为这样就没有全锁住操作共享数据的代码,线程就不安全了
                 synchronized (this){     //也不能锁住while 锁住了就只有一个线程能进来操作了
                     if (number <= 100){
                         try {
                             Thread.sleep(20);
                         } catch (InterruptedException e) {
                             e.printStackTrace();
                         }
                         System.out.println(Thread.currentThread().getName()+":"+number);
                         number++;
                     }else {
                         break;
                     }
                 }
             }
     }
 }

 package com.atguigu.thread;
 ​
 public class CommunicationTest {
     /**
      * 线程通信的例子:实现两个线程交替打印1-100
      * 涉及到的方法:
      * wait():一旦执行此方法,当前线程进入阻塞状态,并释放同步监视器
      * notify():一旦执行此方法,就会唤醒被wait的一个线程,如果有多个线程被wait,则唤醒优先级高的
      * notifyAll():唤醒所有线程
      */
     public static void main(String[] args) {
         Test test = new Test();
         Thread t1 = new Thread(test);
         Thread t2 = new Thread(test);
         Thread t3 = new Thread(test);
         t1.start();
         t2.start();
         t3.start();
     }
 }
 ​
 class Test implements Runnable {
     private int number = 1;
 ​
     @Override
     public void run() {
         synchronized (this) {
             while (true) {
  // while条件不能用number <= 100
  // 因为这样就没有全锁住操作共享数据的代码,线程就不安全了
  // 也不能锁住while 锁住了就只有一个线程能进来操作了
                 //除非使用以下方法来操作线程
                 //先阻塞当前线程,然后再次循环时唤醒被阻塞的线程
                this.notify();//唤醒线程,这个this必须与sychronized锁住的对象相同
                 if (number <= 100) {
                     try {
                         Thread.sleep(20);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     System.out.println(Thread.currentThread().getName() + ":" + number);
                     number++;
                     try {
                         wait();//当前线程阻塞,并释放同步监视器(锁)
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                 } else {
                     break;
                 }
             }
         }
     }
 }

sleep()和wait()方法的异同

  • 相同点:一旦执行,都会让当前线程进入阻塞状态

  • 不同点:

    • 声明的位置不同,sleep声明在Thread类中,wait声明在Object类中。

    • 是否释放同步监视器,如果俩个方法都在同步代码块或同步方法中:sleep()不会释放锁,wait()会释放锁

    • 调用的要求不同:sleep可以在任何需要的场景下调用,wait必须在同步代码块或同步方法中使用。

线程通信的应用:经典例题: 生产者消费者问题

 /**
  * 线程通信的应用:经典例题: 生产者消费者问题
  */
 public class ProduceConsumerTest {
     public static void main(String[] args) {
         Clerk clerk = new Clerk();
         Producer p1 = new Producer(clerk);
         Consumer c1 = new Consumer(clerk);
         p1.start();
         c1.start();
     }
 }
 class Clerk{
     private int product = 0;
 ​
     public void produce() {
         while(true){
 ​
             synchronized (this){
                 this.notify();
                 if(product < 20){
                     try {
                         Thread.sleep(10);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     product++;
                     System.out.println(Thread.currentThread().getName()+"生产者生产产品"+product);
 ​
                 }else {
                     try {
                         wait();
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                 }
             }
         }
     }
 ​
     public void consume() {
         while (true) {
             synchronized (this) {
                 this.notify();
                 if (product > 0) {
                     try {
                         Thread.sleep(10);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     product--;
                     System.out.println(Thread.currentThread().getName() + "消费者消费产品" + product);
                     this.notify();
                 } else {
                     try {
                         wait();
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                 }
             }
         }
     }
 }
 ​
 class Producer extends Thread{
 ​
     private Clerk clerk;
 ​
     public Producer(Clerk clerk){
         this.clerk=clerk;
     }
     @Override
     public void run() {
         clerk.produce();
     }
 }
 ​
 class Consumer extends Thread{
 ​
     private Clerk clerk;
 ​
     public Consumer(Clerk clerk){
         this.clerk=clerk;
     }
     @Override
     public void run() {
         clerk.consume();
     }
 }

欢迎加入学习交流群:166543371


点击全文阅读


本文链接:http://zhangshiyu.com/post/37001.html

卖票  线程  同步  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1