4.多线程之同步
一、同步:synchronized
同步 并发 多个线程访问同一资源,确保资源安全---->线程安全
- 同步块:
Synchronized(引用类型 | this | 类.class){
}
- 同步方法: public static synchronized void.... ---->Web12306
web12306代码实现:
package com.cust.syn; /** * * 描述:同步 并发 多个线程访问同一资源 * synchronized 线程安全 * @author cookie */ public class SynDemo01 { public static void main(String[] args) { //真实角色 Web12306 w = new Web12306(); //三个代理角色 Thread t1 = new Thread(w,"路人甲"); Thread t2 = new Thread(w,"黄牛乙"); Thread t3 = new Thread(w,"攻城狮"); t1.start(); t2.start(); t3.start(); } } class Web12306 implements Runnable { private boolean flag = true; int num = 10; @Override public void run() { while(flag){ test5(); } } //锁定资源不正确 --->线程不安全 速率比较高 public void test5() { // a b c synchronized ((Integer) num) { // 锁定 if (num <= 0) { flag = false;// 线程结束 return; } // a b c try { Thread.sleep(500);// Runnable无法往外抛出异常 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "抢到了第张"+ num-- + "票"); } }// a b = 0 c = -1 //锁定范围不正确 --->线程不安全 速率比较高 public void test4(){ // a b c synchronized(this){ // 锁定 调用此方法的对象 即 Web12306 if(num <=0){ flag = false;//线程结束 return; } } // a b c try { Thread.sleep(500);//Runnable无法往外抛出异常 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了第张"+ num-- +"票"); }//a b = 0 c = -1 //锁定同步块 --->线程安全 速率较低 public void test3(){ synchronized(this){ // 锁定 调用此方法的对象 即 Web12306 if(num <=0){ flag = false;//线程结束 return; } try { Thread.sleep(500);//Runnable无法往外抛出异常 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了第张"+ num-- +"票"); } } //锁定方法 --->线程安全 速率较低 public synchronized void test2(){ if(num <=0){ flag = false;//线程结束 return; } try { Thread.sleep(500);//Runnable无法往外抛出异常 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了第张"+ num-- +"票"); } //并发 不处理 ---->线程不安全 速率较低 public void test1(){ if(num <=0){ flag = false;//线程结束 return; } try { Thread.sleep(500);//Runnable无法往外抛出异常 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了第张"+ num-- +"票"); } }
二、单例模式
懒汉式 和 饿汉式
package com.cust.syn; /** * 单例模式 * gc JVM 垃圾桶 Runtime * 懒汉式: double checking 双重检查 * 1.构造器私有化 * 2.声明一个私有的静态变量 * 3.创建一个共有的静态方法,访问变量,并确保有变量 * 饿汉式: * * @author cookie */ public class SingletonDemo { } /** * 懒汉式: double checking 双重检查 * 1.构造器私有化 * 2.声明一个私有的静态变量 * 3.创建一个共有的静态方法,访问变量,并确保有变量 * @author cookie */ class JVM{ private static JVM jvm; private JVM(){ } public static JVM getInstance(){ if(null == jvm){ //提高效率,在对象已经存在的情况下不进入该方法 synchronized(JVM.class){ //静态方法中不能调用this if(null==jvm){ //如果不存在,则创建对象 安全 jvm = new JVM(); } } } return jvm; } } /** * 饿汉式: * 1.构造器私有化 * 2.声明一个私有的静态变量,并同时实例化该变量 * 3.创建一个共有的静态方法,访问变量 * @author cookie */ class JVM2{ private static JVM2 jvm = new JVM2(); private JVM2(){ } public static JVM2 getInstance(){ //不使用这个方法,变量可能被初始化 return jvm; } } /** * 类在使用时加载,延缓加载时间(MyJvm) 饿汉式推荐 * @author cookie */ class JVM3{ private static class MyJvm{ private static JVM3 jvm = new JVM3(); } private JVM3(){ } public static JVM3 getInstance(){//不使用这个方法,不会加载MyJvm return MyJvm.jvm; } }
三、死锁:过多的同步容易造成死锁
/** * * 描述:死锁:过多的同步容易造成死锁 * @author cookie */ public class SynDemo03 { public static void main(String[] args) { Object g = new Object(); Object m = new Object(); Test t1 = new Test(g,m); Test2 t2 = new Test2(g,m); Thread proxy = new Thread(t1); Thread proxy2 = new Thread(t2); proxy.start(); proxy2.start(); } } class Test implements Runnable{ Object goods; Object money; public Test(Object goods, Object money) { this.goods = goods; this.money = money; } @Override public void run() { test(); } public void test(){ synchronized(goods){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(money){ } } System.out.println("一手给钱"); } } class Test2 implements Runnable{ Object goods; Object money; public Test2(Object goods, Object money) { this.goods = goods; this.money = money; } @Override public void run() { test(); } public void test(){ synchronized(money){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(goods){ } } System.out.println("一手给货"); } }
四、解决死锁:生产者消费者 信号量法
package com.cust.pro; /** * 一个场景 共同的资源 生产者消费者模式 信号灯法 Object: wait() 释放锁 等待 sleep()不释放锁 * notify()/notifyAll() 唤醒等待 * * @author cookie */ class Movie { private String pic; // 信号灯 // 信号灯法 // flag---->T 生产者生产,消费者等待,生产完生产毕后,唤醒消费者 // flag---->F 消费者消费,生产者等待,消费者消费完毕后,唤醒生产者 private boolean flag = true; public synchronized void play(String pic) { if (!flag) {// 消费者消费 生产者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } try { Thread.sleep(100); } catch (InterruptedException e1) { e1.printStackTrace(); } // 生产结束 this.pic = pic; System.out.println("生产了:" + pic); // 唤醒消费者, this.notifyAll(); // 生产者结束 this.flag = false; } public synchronized void watch() { if (flag) {// 生产者生产,消费者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 消费者消费 try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } // 消费完毕 System.out.println("消费了:" + this.pic); // 唤醒生产者 this.notify(); // 消费者等待 this.flag = true; } } class Player implements Runnable{ private Movie m; public Player(Movie m) { this.m = m; } @Override public void run() { for (int i = 0; i < 20; i++) { if(0==i%2){ m.play("左青龙"); }else{ m.play("右白虎"); } } } } class Watcher implements Runnable{ private Movie m; public Watcher(Movie m) { this.m = m; } @Override public void run() { for (int i = 0; i < 20; i++) { m.watch(); } } } public class App { public static void main(String[] args) { //共同的资源 Movie m = new Movie(); //多线程 Player p = new Player(m); Watcher w = new Watcher(m); new Thread(p).start(); new Thread(w).start(); } }