多线程-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()。(公平锁:先到先得,公平嘛)。
---------------------------------------------------------------------------------
作者:PuPile
本博客所有文章仅用于学习、研究和交流目的,欢迎非商业性质转载。
博主的文章没有高度、深度和广度,只是凑字数。由于博主的水平不高,不足和错误之处在所难免,希望大家能够批评指出。
博主是利用读书、参考、引用、抄袭、复制和粘贴等多种方式打造成自己的文章,请原谅博主成为一个无耻的文档搬运工!

浙公网安备 33010602011771号