• 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();
    	}
    }
    

      

  • 相关阅读:
    centos 配置静态ip
    mysql常用命令
    mac 安装好mysql后密码重置
    安装Intellij Idea14/15
    freemarker 学习一 入门小例子
    获取类路径
    mysql中的int smallint 取值范围
    MySQL按照汉字的拼音排序
    Log4j 基本配置
    追加写入
  • 原文地址:https://www.cnblogs.com/blogofcookie/p/5930168.html
Copyright © 2020-2023  润新知