【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;
	}

}
相關文章
相關標籤/搜索