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

  

原文地址:https://www.cnblogs.com/blogofcookie/p/5930168.html