//这次吸取了之前做实验的教训,在做实验之前,先把书上的有关代码都敲了一次...虽然好像没什么用,因为实验还是做得很艰难...不过这次实验本来就难,所以也许其实是有用的,只是我没感受到罢了...
//TaskThreadDemo.java
public class TaskThreadDemo
{
public static void main(String[] args)
{
//Create tasks
Runnable printA = new PrintChar('a', 100);
Runnable printB = new PrintChar('b', 100);
Runnable print100 = new PrintNum(100);
//Create threads
Thread thread1 = new Thread(printA);
Thread thread2 = new Thread(printB);
Thread thread3 = new Thread(print100);
//Run threads
thread1.start();
thread2.start();
thread3.start();
}
}
class PrintChar implements Runnable
{
//The task for printing a character a specified number of times
private char charToPrint; //The character to print
private int times;// The number of times to repeat
//Construct a task with specified character and number of times to print the character
public PrintChar(char c, int t)
{
charToPrint = c;
times = t;
}
//Override the run() method to tell the system what task to perform
public void run()
{
for (int i = 0; i < times; i++)
System.out.print(charToPrint);
System.out.println();
}
}
//The task for printing numbers from 1 to n for a giving n
class PrintNum implements Runnable
{
private int lastNum;
//Construct a task for printing 1, 2, 3, ..., n
public PrintNum(int n)
{
lastNum = n;
}
//Tell the thread how to run
public void run()
{
for (int i = 1; i <= lastNum; i++)
System.out.print(" " + i);
System.out.println();
}
}
/*重要注意事项:
* 任务中的 run() 方法指明如何完成这个任务。Java虚拟机会自动调用该方法,无需特意调用它。
* 直接调用 run() 只是在同一个线程中执行该方法,而没有新线程被启动
*/
import javax.swing.*;
public class FlashingText extends JApplet implements Runnable
{
private JLabel j1b1Text = new JLabel("Welcome", JLabel.CENTER);
public FlashingText()
{
add(j1b1Text);
new Thread(this).start();
}
// Set the text on/off every 200 milliseconds
public void run()
{
try
{
while (true)
{
if (j1b1Text.getText() == null)
j1b1Text.setText("Welcome");
else
j1b1Text.setName(null);
Thread.sleep(200);
}
}
catch(InterruptedException e) {}
}
}
//改写 TaskThreadDemo.java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorDemo
{
public static void main(String[] args)
{
//Create a fixed thread pool with maximum three threads
ExecutorService executor = Executors.newFixedThreadPool(3);
//Submit runnable tasks to the executor
executor.execute(new PrintChar('a', 100));
executor.execute(new PrintChar('b', 100));
executor.execute(new PrintNum(100));
//Shut down the executor
executor.shutdown();
}
}
class PrintChar implements Runnable
{
//The task for printing a character a specified number of times
private char charToPrint; //The character to print
private int times;// The number of times to repeat
//Construct a task with specified character and number of times to print the character
public PrintChar(char c, int t)
{
charToPrint = c;
times = t;
}
//Override the run() method to tell the system what task to perform
public void run()
{
for (int i = 0; i < times; i++)
System.out.print(charToPrint);
System.out.println();
}
}
//The task for printing numbers from 1 to n for a giving n
class PrintNum implements Runnable
{
private int lastNum;
//Construct a task for printing 1, 2, 3, ..., n
public PrintNum(int n)
{
lastNum = n;
}
//Tell the thread how to run
public void run()
{
for (int i = 1; i <= lastNum; i++)
System.out.print(" " + i);
System.out.println();
}
}
//如果需要为一个任务创建一个线程,就使用Thread类。如果需要为多个任务创建线程,最好使用线程池
//此例用于引入“竞争状态”和“线程安全的”这两个概念
//当所有线程同时访问同一个数据时,就会出现数据破坏的问题
import java.util.concurrent.*;
public class AccountWithoutSync
{
private static Account account = new Account();
public static void main(String[] args)
{
ExecutorService executor = Executors.newCachedThreadPool();
// Create and launch 100 threads
for (int i = 0; i < 100; i++)
executor.execute(new AddAPennyTask());
executor.shutdown();
while (!executor.isTerminated()) {}
System.out.println("What is balance? " + account.getBalance());
}
// A thread for adding a penny to account
private static class AddAPennyTask implements Runnable
{
public void run()
{
account.deposit(1);
}
}
// An inner class for account
private static class Account
{
private int balance = 0;
public int getBalance()
{
return balance;
}
public void deposit(int amount)
{
int newBalance = balance + amount;
// This delay is deliberately added to magnify the data-corruption problem and make it easy to see.
try
{
Thread.sleep(5);
}
catch(InterruptedException e) {}
balance = newBalance;
}
}
}
//使用显示锁来修改 AccountWithoutSync.java
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
public class AccountWithSyncUsingLock
{
private static Account account = new Account();
public static void main(String[] args)
{
ExecutorService executor = Executors.newCachedThreadPool();
// Create and launch 100 threads
for (int i = 0; i < 100; i++)
executor.execute(new AddAPennyTask());
executor.shutdown();
// Wait until all tasks are finished
while (!executor.isTerminated()) {}
System.out.println("What is balance? " + account.getBalance());
}
// A thread for adding a penny to account
private static class AddAPennyTask implements Runnable
{
public void run()
{
account.deposit(1);
}
}
// An inner class for account
private static class Account
{
private static Lock lock = new ReentrantLock(); // Create a lock
private int balance = 0;
public int getBalance()
{
return balance;
}
public void deposit(int amount)
{
lock.lock(); // Acquire the lock
try
{
int newBalance = balance + amount;
// This delay is deliberately added to magnify the data-corruption problem and make it easy to see.
Thread.sleep(5);
balance = newBalance;
}
catch(InterruptedException e) {}
finally
{
lock.unlock(); // Release the lock
}
}
}
}
// 对 lock() 的调用之后紧随一个 try-catch 块并且在 finally 子句中释放这个锁是比较好的写法,可以确保锁被释放
// 通常,使用 synchronized 方法或语句必使用相互排斥的显示锁简单些。然而,使用显示锁对同步具有状态的线程更加直观和灵活
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
public class ThreadCooperation
{
private static Account account = new Account();
public static void main(String[] args)
{
// Create a thread pool with two threads
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(new DepositTask());
executor.execute(new WithdrawTask());
executor.shutdown();
System.out.println("Thread 1\t\tThread 2\t\tBalance");
}
public static class DepositTask implements Runnable
{
public void run()
{
try
{ // Purposely delay it to let the withdraw method proceed
while(true)
{
account.deposit((int)(Math.random() * 10) + 1);
Thread.sleep(1000);
}
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
// A task for subtracting an amount from the account
public static class WithdrawTask implements Runnable
{
public void run()
{
}
}
// An inner class for account
private static class Account
{
private static Lock lock = new ReentrantLock(); // Create a lock
// Create a condition
private static Condition newDeposit = lock.newCondition();
private int balance = 0;
public int getBalance()
{
return balance;
}
public void withdraw(int amount)
{
lock.lock(); // Acquire the lock
try
{
while (balance < amount)
{//注意:此处的 while 语句如果换为 if语句,提款任务可能永久等待。如果使用循环语句,则提款任务可以有重新检验条件的机会。因此,应该在循环语句中测试条件
System.out.println("\t\t\tWait for a deposit");
newDeposit.await();
}
balance -= amount;
System.out.println("\t\t\tWithdraw " + amount + "\t\t" + getBalance());
}
catch (InterruptedException e) {}
finally
{
lock.unlock(); // Release the lock
}
}
public void deposit(int amount)
{
lock.lock(); // Acquire the lock
try
{
balance += amount;
System.out.println("Deposit " + amount + "\t\t\t\t\t" + getBalance());
// Signal thread waiting on the condition
newDeposit.signalAll();
}
finally
{
lock.unlock();
}
}
}
}
// 一旦线程调用条件上的 await(),线程就进入等待状态,等待回复的信号。如果忘记对状态调用 signal() 或 signalAll(),那么线程就永远等待下去。
//条件由Lock对象创建。为了调用任意方法(例如,await()、signal()和signalAll()),必须首先拥有锁。如果没有获取锁就调用这些方法,会抛出IllegalMonitorStateException异常
//生产者 / 消费者问题的有关代码
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
public class ConsumerProducer
{
private static Buffer buffer = new Buffer();
public static void main(String[] args)
{
// Create a thread pool with two threads
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(new ProducerTask());
executor.execute(new ConsumerTask());
executor.shutdown();
}
// A task for adding an int to the buffer
private static class ProducerTask implements Runnable
{
public void run()
{
try
{
int i = 1;
while (true)
{
System.out.println("Producer writes " + i);
buffer.write(i++); // Add value to the buffer
// Put the thread to sleep
Thread.sleep((int)(Math.random()) * 10000);
}
}
catch(InterruptedException e)
{e.printStackTrace();}
}
}
private static class ConsumerTask implements Runnable
{
public void run()
{
try
{
while (true)
{
System.out.println("\t\t\tConsumer reads " + buffer.read());
// Put the thread into sleep
Thread.sleep((int)(Math.random() * 10000));
}
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
// An inner class for buffer
private static class Buffer
{
private static final int CAPACITY = 1; // buffer size
private java.util.LinkedList<Integer> queue = new java.util.LinkedList<Integer>();
// Create a new lock
private static Lock lock = new ReentrantLock();
// Create two conditions
private static Condition notEmpty = lock.newCondition();
private static Condition notFull = lock.newCondition();
public void write(int value)
{
lock.lock(); // Acquire the lock
try
{
while (queue.size() == CAPACITY)
{
System.out.println("Wait for notFull condition");
notFull.await();
}
queue.offer(value);
notEmpty.signal(); // Signal notEmpty Condition
}
catch(InterruptedException e)
{e.printStackTrace();}
finally
{
lock.unlock();
}
}
public int read()
{
int value = 0;
lock.lock(); // Acquire the lock
try
{
while (queue.isEmpty())
{
System.out.println("\t\t\tWait for notEmpty condition");
notEmpty.await();
}
value = queue.remove();
notFull.signal(); // Signal notFull condition
}
catch(InterruptedException e)
{e.printStackTrace();}
finally
{
lock.unlock(); // Release the lock
return value;
}
}
}
}
//使用锁和条件同步生产者和消费者线程。在这个程序中,同步已经在 ArrayBlockingQueue 中实现,所以无需进行手动编码
import java.util.concurrent.*;
public class ConsumerProducerUsingBlockingQueue
{
private static ArrayBlockingQueue<Integer> buffer = new ArrayBlockingQueue<Integer>(2);
public static void main(String[] args)
{
// Create a thread pool with two threads
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(new ProducerTask());
executor.execute(new ConsumerTask());
executor.shutdown();
}
// A task for adding an int to the buffer
private static class ProducerTask implements Runnable
{
public void run()
{
try
{
int i = 1;
while (true)
{
System.out.println("Producer writes " + i);
buffer.put(i++); // Add value to the buffer
// Put the thread to sleep
Thread.sleep((int)(Math.random()) * 10000);
}
}
catch(InterruptedException e)
{e.printStackTrace();}
}
}
private static class ConsumerTask implements Runnable
{
public void run()
{
try
{
while (true)
{
System.out.println("\t\t\tConsumer reads " + buffer.take());
// Put the thread into sleep
Thread.sleep((int)(Math.random() * 10000));
}
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
//改写 AccountWithSyncUsingLock.java 中的 Account 内部类
// An inner class for account
private static class Account
{
// Create a semaphore
private static Semaphore semaphore = new Semophore(1);
private int balance = 0;
public int getBalance()
{
return balance;
}
public void deposit(int amount)
{
try
{
semaphore.acquire();
int newBalance = balance + amount;
// This delay is deliberately added to magnify the data-corruption problem and make it easy to see.
Thread.sleep(5);
balance = newBalance;
}
catch(InterruptedException e) {}
finally
{
semaphore.release();
}
}
}
// 将release()方法放到finally子句中,可以确保即使发生异常也能最终释放该许可