标签:
线程安全出现的原因:1. 必须存在两个或者两个以上的线程。2. 多个线程共享着一个资源,而且操作资源的代码有多句。
案例:夫妻俩一起去银行取钱,一个拿着存折, 一个拿着卡,同时取钱。每次取100块,账户的总额是5000块,不准出现 线程安全问题。
1 class BankThread extends Thread{ 2 3 static int count = 5000; //账户的总额 4 5 public BankThread(String name){ 6 super(name); 7 } 8 9 //非静态静态的同步函数 ----- 锁对象this对象。 10 @Override 11 public void run() { 12 getMoney(); 13 } 14 15 //静态的同步函数 ---------->当前方法所属的类的class文件对象。 16 public synchronized static void getMoney(){ 17 while(true){ 18 if(count>0){ 19 System.out.println(Thread.currentThread().getName()+"取走了100块,还剩余"+(count-100)+"块"); 20 count-=100; 21 }else{ 22 System.out.println("取光了..."); 23 break; 24 } 25 } 26 } 27 } 28 29 public class Demo1 { 30 31 public static void main(String[] args) { 32 //创建线程对象 33 BankThread thread1 = new BankThread("老公"); 34 BankThread thread2 = new BankThread("老婆"); 35 //调用start方法启动线程。 36 thread1.start(); 37 thread2.start(); 38 } 39 }
案例:使用线程创建的Runnable方式模拟三个窗口卖票
1 class SaleTickets implements Runnable { 2 3 int num = 50; // 非静态成员变量 4 5 @Override 6 public void run() { // this 7 while (true) { 8 synchronized ("锁") { 9 if (num > 0) { 10 System.out.println(Thread.currentThread().getName() 11 + "卖出了第" + num + "号票"); 12 num--; 13 } else { 14 System.out.println("售罄了..."); 15 break; 16 } 17 } 18 } 19 } 20 } 21 22 public class Demo2 { 23 24 public static void main(String[] args) { 25 // 创建Runnable实现类的对象 26 SaleTickets saleTickets = new SaleTickets(); 27 // 创建三个线程对象 28 Thread t1 = new Thread(saleTickets, "窗口1"); 29 Thread t2 = new Thread(saleTickets, "窗口2"); 30 Thread t3 = new Thread(saleTickets, "窗口3"); 31 // 调用start方法开启线程 32 t1.start(); 33 t2.start(); 34 t3.start(); 35 } 36 37 }
守护线程(后台线程) : 当前一个java应用只剩下守护线程的时候,那么守护线程马上结束。
1 public class Demo3 extends Thread { 2 3 public Demo3(String name){ 4 super(name); 5 } 6 7 @Override 8 public void run() { // 子类抛出的异常类型必须要小于或者等于父类抛出 的异常类型。 9 for(int i = 1 ; i<100 ; i++){ 10 System.out.println(this.getName()+"已经下载了:"+i+"%"); 11 try { 12 Thread.sleep(100); 13 } catch (InterruptedException e) { 14 e.printStackTrace(); 15 } 16 } 17 System.out.println("下载完毕,正在安装更新包!!!"); 18 } 19 20 public static void main(String[] args) { 21 //创建一个线程对象 22 Demo3 d = new Demo3("守护线程"); 23 24 d.setDaemon(true); //设置一个线程为守护线程。 25 //启动线程 26 d.start(); 27 28 for(int i = 0; i < 100 ; i++){ 29 System.out.println(Thread.currentThread().getName()+":"+i); 30 } 31 } 32 }
join方法: 线程让步。需求:模拟小时候打酱油。
1 class Mother extends Thread{ 2 3 @Override 4 public void run() { 5 System.out.println("妈妈洗菜..."); 6 System.out.println("妈妈切菜..."); 7 System.out.println("妈妈发现没有酱油了..."); 8 //通知儿子去打酱油 9 Son s = new Son(); 10 s.start(); 11 try { 12 s.join(); // join 加入 : 如果当前线程执行了join方法,那么当前线程就会让步给新加入的线程先完成任务,然后当前线程才继续的执行自己的任务。 13 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16 } 17 System.out.println("妈妈炒菜..."); 18 System.out.println("全家一起吃饭..."); 19 } 20 } 21 22 //儿子线程 23 class Son extends Thread{ 24 25 @Override 26 public void run() { 27 try { 28 System.out.println("儿子下楼梯"); 29 Thread.sleep(1000); 30 System.out.println("儿子一直往前走..."); 31 System.out.println("儿子买到了酱油..."); 32 System.out.println("儿子跑回来..."); 33 Thread.sleep(1000); 34 System.out.println("儿子把酱油给老妈.."); 35 } catch (InterruptedException e) { 36 e.printStackTrace(); 37 } 38 } 39 } 40 41 public class Demo4 { 42 43 public static void main(String[] args) { 44 Mother m = new Mother(); 45 m.start(); 46 } 47 }
线程的通讯: 当一个线程完成了一个任务的时候,要通知另外一个线程去处理其他 的事情。
wait() 执行了wait方法的线程,会让该线程进入以锁对象建立的线程池中等待。
notify() 如果一个线程执行了notify方法,该线程会唤醒以锁对象建立的线程池中等待线程中的一个.
notifyAll() 把所有的线程都唤醒。
案例:生产者与消费者,生产一个、消费一个。
1 package day0524; 2 3 //产品类 4 class Product{ 5 6 String name; 7 8 int price; 9 10 boolean flag ; //产品是否生成完毕的标识 false为还没有生成完毕, true 生成完毕了. 11 12 } 13 14 //生产者类 15 class Producer extends Thread{ 16 17 //维护一个产品 18 Product p; 19 20 public Producer(Product p){ 21 this.p = p; 22 } 23 24 @Override 25 public void run() { 26 int i = 0; 27 while(true){ 28 synchronized (p) { 29 if(p.flag==false){ 30 if(i%2==0){ 31 p.name = "摩托车"; 32 p.price= 4000; 33 }else{ 34 p.name = "自行车"; 35 p.price = 300; 36 } 37 System.out.println("生产了"+ p.name+" 价格:"+ p.price); 38 i++; 39 //生成完毕 --- 改标识 40 p.flag = true; 41 //唤醒消费者去消费 42 p.notifyAll();; 43 }else{ 44 //如果产品已经生产完毕,应该等待消费者先消费 45 try { 46 p.wait(); 47 } catch (InterruptedException e) { 48 e.printStackTrace(); 49 } 50 } 51 } 52 } 53 } 54 } 55 56 //消费者 57 class Customer extends Thread{ 58 59 //产品 60 Product p; 61 62 public Customer(Product p){ 63 this.p = p; 64 } 65 66 @Override 67 public void run() { 68 while(true){ 69 synchronized (p) { 70 if(p.flag==true){ 71 System.out.println("消费者消费了:"+ p.name+" 价格:"+ p.price); 72 //改标识 73 p.flag = false; 74 p.notifyAll(); 75 }else{ 76 //如果产品已经被消费完毕,应该唤醒生产者去生成 77 try { 78 p.wait(); 79 } catch (InterruptedException e) { 80 e.printStackTrace(); 81 } 82 } 83 } 84 } 85 } 86 } 87 88 public class Demo5 { 89 90 public static void main(String[] args) { 91 //创建一个产品对象 92 Product p = new Product(); 93 //创建线程对象 94 Producer producer = new Producer(p); 95 Customer customer = new Customer(p); 96 //启动线程 97 producer.start(); 98 customer.start(); 99 100 } 101 }
停止线程:如果我们停止的是一个等待状态下的线程,那么需要配合interrupt方法去使用。
1 package day0524; 2 3 public class Demo6 extends Thread { 4 5 boolean flag = true; 6 7 public Demo6(String name) { 8 super(name); 9 } 10 11 @Override 12 public synchronized void run() { 13 int i = 0; 14 while (flag) { 15 try { 16 this.wait(); // 狗娃等待... 17 } catch (InterruptedException e) { 18 System.out.println("接收到了一个InterruptedException.."); // 狗娃 19 } 20 System.out.println(Thread.currentThread().getName() + ":" + i); 21 i++; 22 } 23 } 24 25 public static void main(String[] args) { 26 // 创建线程对象 27 Demo6 d = new Demo6("狗娃"); 28 d.start(); 29 30 // 当主线程的i到80的时候,停止狗娃线程。 31 for (int i = 0; i < 100; i++) { 32 if (i == 80) { 33 d.flag = false; // interrupt() 无法停止一个线程, 34 d.interrupt(); // 强制清除一个线程的wait、 sleep状态。 可以指定清除那个线程。 35 36 } 37 System.out.println(Thread.currentThread().getName() + ":" + i); 38 } 39 } 40 41 }
java同步机制解决了线程安全问题,但是同时也引发了死锁现象。
1 package day0524; 2 3 class DeadLockThread extends Thread { 4 5 public DeadLockThread(String name) { 6 super(name); 7 } 8 9 @Override 10 public void run() { 11 if ("张三".equals(this.getName())) { 12 synchronized ("遥控器") { 13 System.out.println(this.getName() + "取走了遥控器,准备取电池"); 14 synchronized ("电池") { 15 System.out.println(this.getName() + "取到了电池,开着空调爽歪歪的吹着 !!"); 16 } 17 } 18 19 } else if ("李四".equals(this.getName())) { 20 synchronized ("电池") { 21 System.out.println(this.getName() + "取走了电池,准备取取遥控器"); 22 synchronized ("遥控器") { 23 System.out.println(this.getName() + "取走了遥控器,开着空调爽歪歪的吹着 !!"); 24 } 25 } 26 } 27 } 28 } 29 30 public class Demo7 { 31 32 public static void main(String[] args) { 33 // 创建了线程对象 34 DeadLockThread thread1 = new DeadLockThread("张三"); 35 DeadLockThread thread2 = new DeadLockThread("李四"); 36 thread1.setPriority(10); 37 thread2.setPriority(1); 38 // 调用start方法启动线程 39 thread1.start(); 40 thread2.start(); 41 } 42 }
标签:
原文地址:http://www.cnblogs.com/syliuchang/p/4526369.html