練習題目
習題1
思路如下。
線程1:名爲ThreadNum,用於打印1~52
線程2:名爲ThreadChar,用於打印A~Z
用於共享的類:名爲Print,有printNum,printChar方法。
答案如下。(自己寫的,僅供參考)
該項目由Print.java, Demo1.java, ThreadNum.java, ThreadChar.java組成。
public class Print
{
//是否可以打印字母
private boolean flag = false;
public Print() {
super();
}
synchronized int printNum(int num) {
try
{
//可以打印字母
if(flag) {
wait();
}
else //可以打印數字
{
System.out.print(++num);
System.out.print(++num);
flag = true; //可以打印字母
notifyAll(); //釋放同步監視器的鎖,喚醒其他線程
}
}
catch (InterruptedException ite)
{
ite.printStackTrace();
}
return num;
}
synchronized int printChar(int offset) {
try
{
//不可以打印字母
if(!flag) {
wait();
}
else //可以打印字母
{
char c = (char)('A' + offset);
offset++;
if(c == 'Z') {
System.out.println(c);
}
else {
System.out.print(c);
}
flag = false; //不可用打印字母,可以打印數字
notifyAll(); //釋放同步監視器的鎖,喚醒其他線程
}
}
catch (InterruptedException ite)
{
ite.printStackTrace();
}
return offset;
}
}
public class ThreadChar extends Thread
{
private Print p;
private int offset = 0;
public ThreadChar(String name,
Print p) {
super(name);
this.p = p;
}
@Override
public void run() {
while(offset < 26) {
offset = p.printChar(offset);
}
}
}
public class ThreadNum extends Thread
{
private Print p;
private int num = 0;
public ThreadNum(String name,
Print p) {
super(name);
this.p = p;
}
@Override
public void run() {
while(num < 52) {
num = p.printNum(num);
}
}
}
public class Demo1
{
public static void main(String[] args)
throws InterruptedException {
Print p = new Print();
new ThreadNum("打印Num的線程", p).start();
new ThreadChar("打印Char的線程", p).start();
}
}
該項目的另一寫法是:(僅修改Print.java)
import java.util.concurrent.locks.*;
public class Print
{
private final Lock lock = new ReentrantLock();
private final Condition cond = lock.newCondition();
//是否可以打印字母
private boolean flag = false;
public Print() {
super();
}
int printNum(int num) {
//加鎖
lock.lock(); // block until condition holds
try
{
//可以打印字母
if(flag) {
//Causes the current thread to wait until it is signalled or interrupted.
cond.await();
}
else //可以打印數字
{
System.out.print(++num);
System.out.print(++num);
flag = true; //可以打印字母
cond.signalAll(); //Wakes up all waiting threads.
}
}
catch (InterruptedException ite)
{
ite.printStackTrace();
}
finally {
lock.unlock();
}
return num;
}
synchronized int printChar(int offset) {
lock.lock();
try
{
//不可以打印字母
if(!flag) {
//Causes the current thread to wait until it is signalled or interrupted.
cond.await();
}
else //可以打印字母
{
char c = (char)('A' + offset);
offset++;
if(c == 'Z') {
System.out.println(c);
}
else {
System.out.print(c);
}
flag = false; //不可用打印字母,可以打印數字
cond.signalAll(); //Wakes up all waiting threads.
}
}
catch (InterruptedException ite)
{
ite.printStackTrace();
}
finally {
lock.unlock();
}
return offset;
}
}
運行結果如下。
值得注意的是,併發訪問Print時,比如ThreadChar創建的進程,這個進程執行printChar的次數不是(‘Z’-‘A’)次,而是大於(‘Z’-‘A’)次,因爲,進程有可能執行下面的語句。
if(!flag) {
//Causes the current thread to wait until it is signalled or interrupted.
cond.await();
}
因此在ThreadNum和ThreadChar類中run方法的使用的是流程控制中的while語句。
習題2
該項目由Garage.java, Demo.java, ThreadCar.java組成。
public class Garage
{
//表示車庫,true可停車,false不可停車(已停車)
private boolean[] garage = new boolean[]{true, true, true};
private int available() {
for(int i = 0; i < garage.length; i++) {
if(garage[i] == true) {
return i;
}
}
return -1;
}
//@return i
//成功返回車位號,失敗返回-1
public synchronized int park() {
int i = -1;
try
{
//無車位
if((i = available()) < 0) {
wait(); //等待車位空閒
}
else {
garage[i] = false; //已停車
System.out.println(Thread.currentThread().getName() + ":"
+ "在車位號" + i + "停車");
}
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return i; //返回車位號(0/1/2)
}
//成功返回true,失敗返回false
public synchronized boolean out(int id) {
if(garage[id] == false) {
garage[id] = true; //可停車
System.out.println(Thread.currentThread().getName() + ":"
+ "在車位號" + id + "出庫");
notifyAll();
return true;
}
else {
return false;
}
}
}
public class Demo
{
public static void main(String[] args)
{
Garage g = new Garage();
new ThreadCar("Car-0", g).start();
new ThreadCar("Car-1", g).start();
new ThreadCar("Car-2", g).start();
}
}
public class ThreadCar extends Thread
{
private Garage g;
private int id = -1;
private int count = 0;
public ThreadCar(String name, Garage g) {
super(name);
this.g = g;
}
@Override
public void run() {
try
{
while(count < 3) {
//停車失敗,繼續停車
while((id = g.park()) < 0);
sleep(200); //200ms
//如果停車不成功,繼續出庫
while(g.out(id) == false);
count++;
}
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
運行結果如下。