【Java基础】线程同步教程

线程同步

    线程同步是指多个线程对同一资源(同一对象、同一变量等)进行操做,就会产生线程同步的问题。
java

以下:数组

package org.zhanghua.javase.demo.thread;

/**
 * 线程同步演示
 * 
 * @author ZhangHua
 * 
 */
public class SynchronizedTest1 implements Runnable {
	Timer timer = new Timer();

	public static void main(String[] args) {
		SynchronizedTest1 test = new SynchronizedTest1();
		Thread t1 = new Thread(test);
		Thread t2 = new Thread(test);
		t1.setName("t1");
		t2.setName("t2");
		t1.start();
		t2.start();
	}

	@Override
	public void run() {
		timer.add(Thread.currentThread().getName());
	}
}

/**
 * 若是访问公用资源(例如:多个对象同时访问一个资源的时候),就须要同步
 * 
 * @author ZhangHua
 * 
 */
class Timer {
	private static int num = 0;

	// 在方法前加关键字synchronized 表示当程序执行到该方法时,锁定当前对象
	public synchronized void add(String name) {
		// synchronized (this) {
		// 表示在执行这块{}代码的时候,锁定当前对象,其余对象进入不了,只有当这块{}代码执行完了以后,会自动释放当前对象
		num++;
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// e.printStackTrace();
		}
		System.out.println(name + "你是第" + num + "个访问timer的线程");
		// }
	}
}

若是上面不使用synchronized 线程同步,输出的结果会以下:ide

t2你是第2个访问timer的线程
t1你是第2个访问timer的线程

解决方法:this

一、在方法前加关键字synchronized 表示当程序执行到该方法时,锁定当前对象spa

二、使用synchronized (this) {}表示在执行这块{}代码的时候,锁定当前对象,其余对象进入不了,只有当这块{}代码执行完了以后,会自动释放当前对象线程


死锁?如何形成死锁的出现?

2个线程在执行的过程,须要锁定对方对象,才能完成,就会死锁。指针

例如:A 须要锁定B,才能完成;B须要锁定A,才能完成code

package org.zhanghua.javase.demo.thread;

/**
 * 线程死锁演示
 * 
 * @author ZhangHua
 * 
 */
public class DeadLockTest implements Runnable {
	// 状态值
	public int flag = 0;

	static Object o1 = new Object();
	static Object o2 = new Object();

	@Override
	public void run() {
		System.out.println("flag=" + flag);
		if (flag == 1) {
			// 若是flag=1,就执行synchronized{}并锁定,首先锁定o1,而后若是能锁定o2,就能执行完成
			synchronized (o1) {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized (o2) {
					System.out.println("1");
				}
			}
		}
		if (flag == 0) {
			// 若是flag=0,就执行synchronized{}并锁定,首先锁定o2,而后若是能锁定o1,就能执行完成
			// 锁定这2个线程就死锁了
			synchronized (o2) {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized (o1) {
					System.out.println("0");
				}
			}
		}
	}

	/**
	 * 结果猜测: 程序卡死了,不动了,该进程永远运行
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		DeadLockTest d1 = new DeadLockTest();
		d1.flag = 1;
		DeadLockTest d2 = new DeadLockTest();
		d2.flag = 0;
		Thread t1 = new Thread(d1);
		Thread t2 = new Thread(d2);
		t1.start();
		t2.start();
		// 解决死锁的解决方案:能够把锁的对象加大些,若是锁住对象内的2个小对象,有可能发现死锁,那么就加大,锁住整个对象就能够了
	}

}

解决死锁的解决方案:能够把锁的对象加大些,若是锁住对象内的2个小对象,有可能发现死锁,那么就加大,锁住整个对象就能够了对象


生产者与消费者

package org.zhanghua.javase.demo.thread;

/**
 * 生产者与消费者演示
 * 
 * 模拟一个作汉堡包和吃汉堡包的过程
 * 
 * @author Edward
 * 
 */
public class ProducerConsumerDemo {

	public static void main(String[] args) {
		// 大概有以下的概念
		// 汉堡包
		// 生产者
		// 消费者
		// 装汉堡包的容器

		HamburgerStack stack = new HamburgerStack();

		Baker baker = new Baker(stack);

		Customer customer = new Customer(stack);

		Thread b1 = new Thread(baker);
		b1.start();
		Thread c1 = new Thread(customer);
		c1.start();
	}

}

/**
 * 汉堡包
 * 
 * @author Edward
 * 
 */
class Hamburger {

	private Integer id; // 编号 用于汉堡包

	public Hamburger() {
	}

	public Hamburger(Integer id) {
		this.id = id;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	@Override
	public String toString() {
		return "汉堡包" + id;
	}

}

/**
 * 装汉堡包的容器(先进后出)
 * 
 * @author Edward
 * 
 */
class HamburgerStack {

	private Hamburger[] stack = new Hamburger[10]; // 用数组来装汉堡包,最多能够装10个

	private Integer index = 0; // 数组的指针

	/**
	 * 向容器中放汉堡包
	 * 
	 * @param hamburger
	 */
	public synchronized void push(Hamburger hamburger) {
		while (index==stack.length) {
			//就等待
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notifyAll();
		stack[index] = hamburger; // 把汉堡放到第index的位置
		index++; // 更新index
	}

	/**
	 * 从容器中取汉堡包
	 * 
	 * @return
	 */
	public synchronized Hamburger pop() {
		while (index==0) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notifyAll();
		index--;
		return stack[index];
	}

}

/**
 * 面包师傅(生产者)
 * 
 * @author Edward
 * 
 */
class Baker implements Runnable {

	/**
	 * 生产者怎么生成面包呢? 首先得是一个线程类,由于可能有多个面包师傅 首先有有一个装面包的容器
	 */

	private HamburgerStack stack;

	public Baker(HamburgerStack stack) {
		this.stack = stack;
	}

	/**
	 * 面包师傅生产面包
	 * 
	 * 假设每一个面包师傅最多生成20个面包,就完成了工做
	 * 
	 */
	@Override
	public void run() {
		for (int i = 1; i <= 20; i++) {
			// 生成一个面包
			Hamburger hamburger = new Hamburger(i);
			// 向容器中放面包
			stack.push(hamburger);
			System.out.println("我作了一个:"+hamburger);
			// 生产一个面包,休息1000毫秒
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}

	public HamburgerStack getStack() {
		return stack;
	}

	public void setStack(HamburgerStack stack) {
		this.stack = stack;
	}

}

/**
 * 顾客 吃面包的人(消费者)
 * 
 * @author Edward
 * 
 */
class Customer implements Runnable {

	private HamburgerStack stack;

	public Customer(HamburgerStack stack) {
		this.stack = stack;
	}

	/**
	 * 消费过程
	 * 
	 * 从装汉堡的容器中,拿出一个汉堡包,而后吃掉
	 * 
	 */
	@Override
	public void run() {
		for (int i = 1; i <= 20; i++) {
			// 从容器中拿出一个汉堡包
			Hamburger hamburger = stack.pop();
			System.out.println("我吃了一个:" + hamburger);
			// 吃了休息一个1000毫秒
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public HamburgerStack getStack() {
		return stack;
	}

	public void setStack(HamburgerStack stack) {
		this.stack = stack;
	}

}
相关文章
相关标签/搜索