练习1:同步代码段synchronized(this)
public class SyncThread implements Runnable {
private static int count;
public SyncThread() {
count = 0;
}
@Override
public void run() {
/**
* synchronized(this)代码段,相当于同步锁定该方法的对象,等同于synchronized修饰非static方法
*/
synchronized(this) {
for(int i=5;i>0;i--) {
System.out.println(Thread.currentThread().getName()+ ":" + (count++));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
SyncThread st = new SyncThread();
Thread t1 = new Thread(st, "A");
Thread t2 = new Thread(st, "B");
t1.start();
t2.start();
}
}
分析:同步锁加在了this上,当持有该对象的多个线程同时执行到syncronized代码段时,此时锁机制就会发挥作用,保证同一时刻只能有一个线程执行同步代码段。
如果是两个线程持有的是两个不同的对象,此时this就分别是两个不同的对象,就不受限制了,如下所示:
public static void main(String[] args) {
SyncThread st1 = new SyncThread();
SyncThread st2 = new SyncThread();
Thread t1 = new Thread(st1, "A");
Thread t2 = new Thread(st2, "B");
t1.start();
t2.start();
}
练习2:同步代码段synchronized(A.class)和synchronized修饰static方法
/**
* 设计场景,希望count的值在一个方法中先加1,再减1,最后不变。
* @author andy
*
*/
public class SyncThread2 implements Runnable {
private static int count;
public SyncThread2() {
count = 0;
}
public static void addCount() {
System.out.println(Thread.currentThread().getName()+ ":" + (++count));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ ":" + (--count));
}
/**
* synchronized修饰static方法时,相当于同步锁定该类的class,这样该类的所有对象都持有该方法的锁
*/
public static synchronized void addCount2() {
System.out.println(Thread.currentThread().getName()+ ":" + (++count));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ ":" + (--count));
}
/**
* synchronized修饰class时,相当于同步锁定该类的class,这样该类的所有对象都持有该方法的锁
*/
public static void addCount3() {
synchronized(SyncThread2.class) {
System.out.println(Thread.currentThread().getName()+ ":" + (++count));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ ":" + (--count));
}
}
@Override
public void run() {
for(int i=5;i>0;i--) {
//非同步安全,在多线程并发环境中无法完成每个方法执行后count的值不变
addCount();
//同步安全
//addCount2();
}
}
public static void main(String[] args) {
SyncThread2 st1 = new SyncThread2();
SyncThread2 st2 = new SyncThread2();
Thread t1 = new Thread(st1, "A");
Thread t2 = new Thread(st2, "B");
t1.start();
t2.start();
}
}
练习3:综合练习,模拟银行并发存款取款
/**
* 个人银行账户
* @author alex
*
*/
public class Account {
private String accountNo;
private double balance;
private boolean flag = false;
public Account(String _accountNo, double _balance) {
this.accountNo = _accountNo;
this.balance = _balance;
}
public String getAccountNo() {
return accountNo;
}
public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}
public double getBalance() {
return balance;
}
/**
* synchronized修饰非static方法,相当于同步锁定该方法的对象,等同于synchronized(this)代码段
* @param drawBalance
*/
public synchronized void drawBalance(double drawBalance) {
if (flag) {
if (balance > drawBalance) {
System.out.println(Thread.currentThread().getName() + "取钱成功,正在吐钞:" + drawBalance);
balance -= drawBalance;
flag = false;
this.notifyAll();
System.out.println(Thread.currentThread().getName() + "余额为:" + getBalance());
} else {
System.out.println(Thread.currentThread().getName() + "取钱失败,余额不足");
}
} else {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* synchronized修饰非static方法,相当于同步锁定该方法的对象,等同于synchronized(this)代码段
* @param depositBalance
*/
public synchronized void deposit(double depositBalance) {
if (flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println(Thread.currentThread().getName() + " 存款:" + depositBalance);
this.balance += depositBalance;
flag = true;
this.notifyAll();
System.out.println(Thread.currentThread().getName() + "余额为:" + getBalance());
}
}
}
/**
* 存钱线程
* @author andy
*
*/
public class StorerThread implements Runnable {
private Account account;
private double depositBalance;
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public double getDepositBalance() {
return depositBalance;
}
public void setDepositBalance(double depositBalance) {
this.depositBalance = depositBalance;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
account.deposit(depositBalance);
}
}
}
/**
* 取钱线程
* @author andy
*
*/
public class FetcherThread implements Runnable {
private Account account;
private double drawBalance;
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public double getDrawBalance() {
return drawBalance;
}
public void setDrawBalance(double drawBalance) {
this.drawBalance = drawBalance;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
account.drawBalance(drawBalance);
}
}
}
/**
* 模拟银行账户并发存款取款
* @author alex
*
*/
public class AccountSyncTest {
public static void main(String[] args) {
Account acc = new Account("001", 1000);
OfferThread mt1 = new OfferThread();
mt1.setAccount(acc);
mt1.setDrawBalance(20);
Thread t1 = new Thread(mt1, "取钱者1");
Thread t2 = new Thread(mt1, "取钱者2");
FetchThread mt2 = new FetchThread();
mt2.setAccount(acc);
mt2.setDepositBalance(20);
Thread t3 = new Thread(mt2, "存钱者1");
Thread t4 = new Thread(mt2, "存钱者2");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
练习4:线程几种状态切换