1.问题描述
使用不同的方法完成主线程与子线程的同步,要求子线程先执行,在主线程中使用Thread类创建一个子线程,主线程创建后进入阻塞状态,直到子线程运行完毕后唤醒主线程。
2.代码实现
(2.1)方法1--(隐式)使用synchronized关键字
为了保证主线程和子线程互斥的访问临界资源account除了使用对象锁机制实现,还可以采用显式Lock对象实现,线程互斥访问即:使同一时刻只能有一个线程读或写该临界资源,以实现临界区(即访问临界资源的那段代码)对临界资源的访问是互斥进行的。
使用synchronized关键字,包括 设置synchronized语句块 方法和 设置synchronized方法 两种方式,如下所示。
public class ThreadSynchronization {
class Bank{
private int account = 100; //临界资源
//获取account值
public int getAccount(){
return account;
}
//synchronized语句方法,保证线程互斥访问临界资源
//该方法相当于“临界区”
public synchronized void save(int money){
account += money; //访问临界资源account
}
/*
使用第2种方法:使用synchronized代码块
//该方法相当于“临界区”
public void save(int money){
synchronized (this){
account += money; //访问临界资源account
}
}
*/
//采用Runnable创建线程类
class NewThread implements Runnable{
private Bank bank;
public NewThread(Bank bank){
this.bank = bank;
}
@Override
public void run() { //重写 run()
for (int i = 0; i < 10; i++) {
bank.save(10);
System.out.println(i + "账户余额为:" + bank.getAccount());
}
}
}
//建立线程
public void useThread(){
Bank bank = new Bank();//创建实现Runnable接口的实例
NewThread new_Thread = new NewThread(bank);
System.out.println("线程1");
//线程1
Thread thread1 = new Thread(new_Thread);
thread1.start();//启动
System.out.println("线程2");
//线程2
Thread thread2 = new Thread(new_Thread);
thread2.start();//启动
}
public static void main(String[] args) {
ThreadSynchronization st = new ThreadSynchronization();//新建对象st
st.useThread();//调用函数
}
(2.2)方法2--(显式)使用Lock对象表示临界区
为了保证主线程和子线程互斥的访问临界资源account除了使用对象锁机制实现,还可以采用显式Lock对象实现,线程互斥访问即:使同一时刻只能有一个线程读或写该临界资源,以实现临界区(即访问临界资源的那段代码)对临界资源的访问是互斥进行的。
使用Lock对象实现线程互斥的访问临界资源需要通过“ import java.util.concurrent.locks.*; ” 命令对应类库,之后在对应临界资源处使用语句 Lock 对象名 = new ReentrantLock(); 创建Lock对象,之后使用 对象名.lock(); 加锁。对象名.unlock();解锁(无论什么情况下均要执行,因此常放在异常处理的finally语句体中),具体如下所示。
public class ThreadSynchronization {
class Bank{
private int account = 100;
//显示声明Lock对象
private Lock lock = new ReentrantLock();
//获取account值
int getAccount(){
return account;
}
//该方法相当于临界区
public void save(int money){
lock.lock();//加锁
try{
account += money;//访问临界资源account
}finally{
lock.unlock();//解锁
}
}
}
//采用Runnable创建线程类
class NewThread implements Runnable{
private Bank bank;
public NewThread(Bank bank){
this.bank = bank;
}
//重写 run()
@Override
public void run() {
for (int i = 0; i < 10; i++) {
bank.save(10);
System.out.println(i + "账户余额为:" + bank.getAccount());
}
}
}
//建立线程,调用内部类
public void useThread(){
Bank bank = new Bank();//创建实现Runnable接口的实例
NewThread new_Thread = new NewThread(bank);//传递bnak创建NewThread类实例
System.out.println("线程1");
//线程1
Thread thread1 = new Thread(new_Thread);//传递new_Thread创建Thread类实例
thread1.start();//启动
System.out.println("线程2");
//线程2
Thread thread2 = new Thread(new_Thread);//传递new_Thread创建Thread类实例
thread2.start();//启动
}
public static void main(String[] args) {
ThreadSynchronization st = new ThreadSynchronization();
st.useThread();//调用函数
}
3.两种方法运行结果
(注意:Java线程调用 是 “抢占式” 的,因此 每次执行结果得到的线程顺序不同 是正常现象)