線程同步是指多個線程對同一資源(同一對象、同一變量等)進行操做,就會產生線程同步的問題。
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; } }