一、synchronized同步方法
論:“線程安全”與“非線程安全”是多線程的經典問題。synchronized()方法就是解決非線程安全的。
1、方法內的變量為線程安全
public void addI(String username) { try { int num = 0; \\方法內的變量為線程安全 if (username.equals("a")) { num = 100; System.out.println("a set over!"); Thread.sleep(2000); } else { num = 200; System.out.println("b set over!"); } System.out.println(username + " num=" + num); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
2、實例變量非線程安全
public class HasSelfPrivateNum { private int num = 0; \\實例變量非線程安全 public void addI(String username) { try { if (username.equals("a")) { num = 100; System.out.println("a set over!"); Thread.sleep(2000); } else { num = 200; System.out.println("b set over!"); } System.out.println(username + " num=" + num); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
解決方法: 方法前加synchronized關鍵字。
public class HasSelfPrivateNum { private int num = 0; synchronized public void addI(String username) { .............. } }
3、多個對象多個鎖
HasSelfPrivateNum.java
public class HasSelfPrivateNum { private int num = 0; synchronized public void addI(String username) { try { if (username.equals("a")) { num = 100; System.out.println("a set over!"); Thread.sleep(2000); } else { num = 200; System.out.println("b set over!"); } System.out.println(username + " num=" + num); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
ThreadA
public class ThreadA extends Thread { private HasSelfPrivateNum numRef; public ThreadA(HasSelfPrivateNum numRef) { super(); this.numRef = numRef; } @Override public void run() { super.run(); numRef.addI("a"); } }
ThreadB
public class ThreadB extends Thread { private HasSelfPrivateNum numRef; public ThreadB(HasSelfPrivateNum numRef) { super(); this.numRef = numRef; } @Override public void run() { super.run(); numRef.addI("b"); } }
RUN
public class Run { public static void main(String[] args) { HasSelfPrivateNum numRef1 = new HasSelfPrivateNum(); HasSelfPrivateNum numRef2 = new HasSelfPrivateNum(); ThreadA athread = new ThreadA(numRef1); athread.start(); ThreadB bthread = new ThreadB(numRef2); bthread.start(); } }
結果:創建了2個業務實例,產生2個鎖,所以運行結果是異步的。同步為synchronized 異步:asynchronized
4、synchronized 鎖重入
當一個線程得到一個對象鎖時,再次請求該對象鎖時是可以再次得到該對象的鎖的。繼承關系也可重入鎖。
當一個線程執行發生異常時,其持有的鎖會自動釋放。
同步不具有繼承性。的在子類方法中添加synchronized的關鍵字。

public class HasSelfPrivateNum { synchronized public void service1() { System.out.println("service1"); service2(); } synchronized public void service2() { System.out.println("service2"); service3(); } synchronized public void service3() { System.out.println("service3"); } }

public class mYThread extends Thread { @Override public void run() { HasSelfPrivateNum hspn=new HasSelfPrivateNum(); hspn.service1(); } public static void main(String[] args) { mYThread mYThread=new mYThread(); mYThread.start(); } }
二、synchronized同步快
synchronized同步方法持有鎖后,如果長時間不釋放,那另一個線程就必須長時間等待。。這種情況下synchronized同步快來解決
使用方法如圖:
1、synchronized同步快之間具有同步性,當線程訪問object的一個 synchronized(this)同步代碼塊時,其他線程對同一個object對象中所有其他的
synchronized(this)同步代碼塊的訪問會被阻塞。
2、synchronized(this)同步代碼塊是鎖定當前對象的。
1、synchronized同步快解決同步方法效率低得弊端

public class Task { private String getData1; private String getData2; public synchronized void doLongTimeTask() { try { System.out.println("begin task"); Thread.sleep(3000); getData1 = "長時間處理任務后從遠程返回的值1 threadName=" + Thread.currentThread().getName(); getData2 = "長時間處理任務后從遠程返回的值2 threadName=" + Thread.currentThread().getName(); System.out.println(getData1); System.out.println(getData2); System.out.println("end task"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }

public class MyThread1 extends Thread { private Task task; public MyThread1(Task task) { super(); this.task = task; } @Override public void run() { super.run(); CommonUtils.beginTime1 = System.currentTimeMillis(); task.doLongTimeTask(); CommonUtils.endTime1 = System.currentTimeMillis(); } }

public class MyThread2 extends Thread { private Task task; public MyThread2(Task task) { super(); this.task = task; } @Override public void run() { super.run(); CommonUtils.beginTime2 = System.currentTimeMillis(); task.doLongTimeTask(); CommonUtils.endTime2 = System.currentTimeMillis(); } }

public class CommonUtils { public static long beginTime1; public static long endTime1; public static long beginTime2; public static long endTime2; }

public class Run { public static void main(String[] args) { Task task = new Task(); MyThread1 thread1 = new MyThread1(task); thread1.start(); MyThread2 thread2 = new MyThread2(task); thread2.start(); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } long beginTime = CommonUtils.beginTime1; if (CommonUtils.beginTime2 < CommonUtils.beginTime1) { beginTime = CommonUtils.beginTime2; } long endTime = CommonUtils.endTime1; if (CommonUtils.endTime2 > CommonUtils.endTime1) { endTime = CommonUtils.endTime2; } System.out.println("耗時:" + ((endTime - beginTime) / 1000)); } }
修改Task

public class Task { private String getData1; private String getData2; public void doLongTimeTask() { try { System.out.println("begin task"); Thread.sleep(3000); String privateGetData1 = "長時間處理任務后從遠程返回的值1 threadName=" + Thread.currentThread().getName(); String privateGetData2 = "長時間處理任務后從遠程返回的值2 threadName=" + Thread.currentThread().getName(); synchronized (this) { getData1 = privateGetData1; getData2 = privateGetData2; } System.out.println(getData1); System.out.println(getData2); System.out.println("end task"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }