多線程同步
舉個銀行取錢的例子來說
public class ThreadTest13 {
public static void main(String[] args) {
Account account=new Account("叫我男神O(∩_∩)O",5000);
Thread t1=new Thread(new Processor(account));
Thread t2=new Thread(new Processor(account));
t1.start();
t2.start();
}
}
//取款的線程
class Processor implements Runnable{
//賬戶
Account act;
Processor(Account act){
this.act=act;
}
public void run() {
act.withdraw(1000);
System.out.println(act.getActno()+"取款1000塊成功,餘額:"+act.getbalance());
}
}
//賬戶
class Account{
//屬性
private String actno;
private double balance;
//構造方法
public Account() {}
public Account(String actno,double balance) {
this.setActno(actno);
this.setbalance(balance);
}
//set and get
public String getActno() {
return actno;
}
public void setActno(String actno) {
this.actno=actno;
}
public double getbalance() {
return balance;
}
public void setbalance(double balance) {
this.balance=balance;
}
//對外提供一個取款的方法
public synchronized void withdraw(double money) {
synchronized (this) {
//把要同步的代碼放到同步語句塊
/*
* 原理t1 和t2
* t1線程執行到此處,遇到的synchroized這個關鍵字,就回去找this對象鎖
*如果找到了this對象鎖,則進入同步語句塊中執行程序,當同步語句塊中代碼執行結束,t1線程歸還this對象鎖。
*
* 在t1線程執行同步語句塊過程中,如果t2線程也過來執行以下程序,也會遇到synchronzed關鍵字,所以也去找this對象鎖,但是該對象鎖被t1線程持有,只能在此處等待this對象鎖的歸還
*/
double after=balance-money;
//更新
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setbalance(after);
}
}
}
關於synchronized(鎖)的小方面
t1與t2共享一個資源時(同一個進程的線程是共享其進程的*內存和資源*
共享的內存是*堆內存和方法內存* 棧內存不共享,每個線程有自己的棧空間(一個線程一個棧))
public class ThreadTest14 {
public static void main(String[] args) throws InterruptedException {
// TODO 自動生成的方法存根
MyClass mc =new MyClass();
F a=new F(mc);//t1與t2共享一個mc
Thread t1=new Thread(a);
t1.setName("t1");
Thread t2=new Thread(a);
t2.setName("t2");
t1.start();
//保證t1先執行
Thread.sleep(1000);
t2.start();
}
}
class F implements Runnable{
MyClass mc;
F(MyClass mc){
this.mc=mc;
}
public void run() {
if (Thread.currentThread().getName().equals("t1"))
mc.m1();
if(Thread.currentThread().getName().equals("t2"))
mc.m2();
}
}
class MyClass{
public synchronized void m1() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("m1...");
}
// public void m2() { m2不需要等m1結束m2 沒有synchronized關鍵字
// System.out.println("m2....");
// }
public synchronized void m2(){//m2方法會等m1結束 t1和t2共享一個mc ,並且m1和m2都有synchronized
System.out.println("m2......");
}
}
第一次m2沒加synchronized關鍵字(沒和m1公用一個茅坑)
第二次m2加了synchronized關鍵字(和m1共同享用一個茅坑)
對象鎖(不止一個)
m2方法不會等m1方法結束 ,t1和t2不共享同一mc內存。
public class ThreadTest15 {
public static void main(String[] args) throws Exception {
MyClass01 mc1 = new MyClass01();
MyClass01 mc2 = new MyClass01();
B b1 = new B(mc1);
B b2 = new B(mc2);
//*t1與t2 不共享同一mc內存*
Thread t1 = new Thread(b1);
t1.setName("t1");
Thread t2 = new Thread(b2);
t2.setName("t2");
t1.start();
//保證t1先執行
Thread.sleep(1000);
t2.start();
}
}
class B implements Runnable{
MyClass01 mc;
B(MyClass01 mc){
this.mc = mc;
}
@Override
public void run() {
if (Thread.currentThread().getName().equals("t1")) {
mc.m1();
}
if (Thread.currentThread().getName().equals("t2")) {
mc.m2();
}
}
}
class MyClass01{
public synchronized void m1(){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("m1....");
}
//m2方法不會等m1方法結束 ,t1和t2不共享一個mc
public synchronized void m2(){
System.out.println("m2......");
}
}
類鎖(只有一個,synchronized+靜態方法)
因爲有synchronized添加到靜態方法上面的,線程執行到此方法會找類鎖m2方法等m1方法結束之後才能執行,雖然t1與t2的mc對象不一樣,但是m2方法還是會等m1的
(就好像兩個人,分別去兩個不同的茅坑上廁所,但是隻有你手裏有一瓢水可以衝,他不確定他上的時候有沒有水衝,所以得等你上完,再拿水上)
/*
* 類鎖 類只有一個 所以是類級別的,只有一個
* */
public class ThreadTest16 {
public static void main(String[] args) throws Exception {
MyClass03 mc1 = new MyClass03();
MyClass03 mc2 = new MyClass03();
Thread t1 = new Thread(new D(mc1));
Thread t2 = new Thread(new D(mc2));
t1.setName("t1");
t2.setName("t2");
t1.start();
Thread.sleep(1000);
t2.start();
}
}
class D implements Runnable{
MyClass03 mc;
D(MyClass03 mc){
this.mc = mc;
}
public void run(){
if ("t1".equals(Thread.currentThread().getName())) {
mc.m1();//用的還是類鎖 和對象沒有關係
}
if("t2".equals(Thread.currentThread().getName())){
mc.m2();
}
}
}
class MyClass03{
//synchronized 添加到靜態方法上面的,線程執行到此方法會找類鎖
public synchronized static void m1(){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("m1......");
}
//m2方法等m1方法結束之後才能執行,因爲有synchronized
//線程執行該代碼需要類鎖 但是類鎖只有一個
public synchronized static void m2(){
System.out.println("m2......");
}
}
Thread.setDaemon(true);
*守護線程
等其他用戶線程全部結束後則守護線程退出