多线程-3

JAVA线程

线程的安全问题:

举个栗子:

售货员买票:三个售货员同时买票,并且票数一定。

public static void main(String[] args) {
        Runnable run = new Ticket();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }
    static class Ticket implements Runnable {
        //总票数
        private int count = 10;
        @Override
        public void run() {
            while (true) {
                if (count > 0) {
                    //卖票
                    System.out.println("正在准备买票");
                    try {
                        Thread.sleep(1000);//时间差,导致其他线程进入
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count--;
                    System.out.println(Thread.currentThread().getName() + ":出票成功,剩余:" + count);
                    //打印出-1,-2
                } else {
                    break;
                }
            }
        }
    }
正在准备买票
正在准备买票
正在准备买票
Thread-0:出票成功,剩余:7
正在准备买票
Thread-1:出票成功,剩余:8
正在准备买票
Thread-2:出票成功,剩余:8
正在准备买票
Thread-2:出票成功,剩余:6
正在准备买票
Thread-0:出票成功,剩余:4
正在准备买票
Thread-1:出票成功,剩余:5
正在准备买票
Thread-1:出票成功,剩余:3
正在准备买票
Thread-2:出票成功,剩余:2
正在准备买票
Thread-0:出票成功,剩余:2
正在准备买票
Thread-1:出票成功,剩余:1
正在准备买票
Thread-2:出票成功,剩余:0
Thread-0:出票成功,剩余:-1
Thread-1:出票成功,剩余:-2

出现负数的票数。这就是线程不安全的情况,线程休眠的情况导致其他线程会趁虚而入(抢占式调度嘛)。

如何解决:1,使用同步代码块

 1   public static void main(String[] args) {
 2         //线程不安全
 3         //解决方案1:同步代码块
 4         /*
 5         Object o = new Object();
 6         格式: synchronized(锁对象){
 7         }
 8          */
 9         Runnable run = new Ticket();
10         new Thread(run).start();
11         new Thread(run).start();
12         new Thread(run).start();
13     }
14     static class Ticket implements Runnable {
15         //总票数
16         private int count = 10;
17         private Object o = new Object();//同一把锁,即公锁
18         @Override
19         public void run() {
20            //Object o = new Object();//如果将锁对象new在这里,导致每个线程都有自己的锁,这样还是会发生线程不安全,因为每个线程只关注自己的锁。注意!!
21             while (true) {
22                 synchronized (o) {
23                     if (count > 0) {
24                         //卖票
25                         System.out.println("正在准备买票");
26                         try {
27                             Thread.sleep(1000);//时间差,导致其他线程进入
28                         } catch (InterruptedException e) {
29                             e.printStackTrace();
30                         }
31                         count--;
32                         System.out.println(Thread.currentThread().getName() + ":出票成功,剩余:" + count);                  
34                     } else {
35                         break;
36                     }
37                 }
38             }
39         }
40     }

2、同步方法

 1  public static void main(String[] args) {
 2         //线程不安全
 3         //解决方案2:同步方法
 4 
 5         Runnable run = new Ticket();
 6         new Thread(run).start();
 7         new Thread(run).start();
 8         new Thread(run).start();
 9 
10         /*new Thread(new Ticket()).start();
11         new Thread(new Ticket()).start();
12         new Thread(new Ticket()).start();
13         这样相当于没锁,注意!!*/
14     }
15     static class Ticket implements Runnable {
16         //总票数
17         private int count = 10;
18         //给方法添加synchronized
19         public  synchronized boolean sale(){
22             if (count > 0) {
23                 //卖票
24                 System.out.println("正在准备买票");
25                 try {
26                     Thread.sleep(1000);//时间差,导致其他线程进入
27                 } catch (InterruptedException e) {
28                     e.printStackTrace();
29                 }
30                 count--;
31                 System.out.println(Thread.currentThread().getName()+":出票成功,剩余:" + count);
32                 return true;
33             }else {
34                 return false;
35             }
36         }
37         @Override
38         public void run() {
39             while (true) {
40                 boolean flag =  sale();
41                 if(!flag){
42                     break;
43                 }
44             }
45         }
46     }
正在准备买票
Thread-0:出票成功,剩余:9
正在准备买票
Thread-0:出票成功,剩余:8
正在准备买票
Thread-0:出票成功,剩余:7
正在准备买票
Thread-0:出票成功,剩余:6
正在准备买票
Thread-0:出票成功,剩余:5
正在准备买票
Thread-0:出票成功,剩余:4
正在准备买票
Thread-0:出票成功,剩余:3
正在准备买票
Thread-0:出票成功,剩余:2
正在准备买票
Thread-0:出票成功,剩余:1
正在准备买票
Thread-0:出票成功,剩余:0

Process finished with exit code 0

两种方法结果如上图。

3、显示锁 Lock

 1 public static void main(String[] args) {
 2         //线程不安全
 3         //解决方案3:显示锁 Lock 子类 ReentrantLock
 4         Runnable run = new Ticket();
 5         new Thread(run).start();
 6         new Thread(run).start();
 7         new Thread(run).start();
 8     }
 9     static class Ticket implements Runnable {
10         //总票数
11         private int count = 10;
12         //显示锁 :fair参数为true 就表示公平锁
13         private Lock l = new ReentrantLock(true);
14         @Override
15         public void run() {
16             while (true) {
17                 l.lock();
18                 if (count > 0) {
19                     //卖票
20                     System.out.println("正在准备买票");
21                     try {
22                         Thread.sleep(1000);//时间差,导致其他线程进入
23                     } catch (InterruptedException e) {
24                         e.printStackTrace();
25                     }
26                     count--;
27                     System.out.println(Thread.currentThread().getName()+":出票成功,剩余:" + count);
28                 }else {
29                     break;
30                 }
31                 l.unlock();
32             }
33         }
34     }

记得用完要解锁unlock()。(公平锁:先到先得,公平嘛)。

 

posted @ 2020-12-25 19:36  PuPile  阅读(128)  评论(0)    收藏  举报