如果不重写Thread类的其他方法,创建子线程的最好方式是实现Runnable接口。
通常希望主线程再最后结束,isAlive()可以判断线程是否再运行,通常使用join()方法来等待线程结束。
实现线程线程间的互斥(同步):
- 使用synchronized关键字,当修饰代码块时,括号中要填写互斥(同步)对象的引用(悲观锁)
synchronized(){
}
- 使用显式的lock(java.util.concurrent.Lock)(乐观锁):
java.util.concurrent.Lock lock = new java.util.concurrent.
ReentrantLock();
lock.lock();
lock.unlock();
- semaphore:当将信号量设置为1时,就能实现互斥操作
java.util.concurrent.Semaphore = new Semaphore(1);
线程间的通信可以使用wait()、notify()、notifyAll()来使某一些线程等待或者唤醒,其中wait()使线程等待,notify()唤醒等待队列的某一线程,而notifyAll()唤醒等待队列里的所有线程(
注意:这几种方法只能在synchronized上下文中调用)
- wait():通知调用线程放弃监视器并进入休眠,直到其他一些线程进入同一个监视器并调用notify()方法
- notify():唤醒调用相同对象的wait()方法的线程
- notifyAll():唤醒调用相同对象的wait()方法的所有线程,其中的一个线程将得到访问权限
使用wait()和notify()方法实现的生产者/消费者问题:
仓库:
package producerConsumer;
public class Storage {
private int storage = 0;
// Indicate whose turn it is.
private boolean flag = true;
public synchronized void put(int amount) {
try {
// If it is get's turn
while (flag) {
// wait until get finishes
wait();
}
// If not
storage += amount;
System.out.println("Put: " + amount + ", Total: " + storage);
Thread.sleep(1000);
// Notify that it is ready to get.
flag = true;
// awaken get thread.
notify();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized void get(int amount) {
try {
// If there is enough to get and it is put's turn.
while (amount > storage || !flag) {
System.out.println("Want to get: " + amount);
// enable put thread
flag = false;
// awaken put thread
notify();
// wait until put thread notify()
wait();
}
storage -= amount;
System.out.println("Get: " + amount + ", total: " + storage);
Thread.sleep(1000);
// Notify put that get has finished
flag = false;
notify();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public int getStorage() {
return storage;
}
}
生产者:
package producerConsumer;
import java.util.Random;
public class Producer implements Runnable{
Storage s;
public Producer(Storage s) {
// TODO Auto-generated constructor stub
this.s = s;
new Thread(this, "producer").start();
}
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
s.put((new Random()).nextInt(10));
}
}
}
消费者:
package producerConsumer;
import java.util.Random;
public class Consumer implements Runnable {
Storage s;
public Consumer(Storage s) {
// TODO Auto-generated constructor stub
this.s = s;
new Thread(this, "consumer").start();
}
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
s.get((new Random()).nextInt(20));
}
}
}
主函数:
package producerConsumer;
public class PCTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Storage storage = new Storage();
new Producer(storage);
new Consumer(storage);
}
}
当然,除了这种方法实现生产者/消费者问题之外,使用之前提到的三种方法也是可以实现的,只不过不能使得进程一直等待,所以要把put和get函数中的while(true)循环删除或者变成if判断,以免线程阻塞。