1. 使用synchronized(互斥)解决代码冲突问题
public class TestSynchronizedThread {
/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
Thread t1 = new Thread(new Adder());
Thread t2 = new Thread(new Adder());
Thread t3 = new Thread(new Adder());
Thread t4 = new Thread(new Subtracter());
Thread t5 = new Thread(new Subtracter());
Thread t6 = new Thread(new Subtracter());
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
System.out.println(Counter.getId());
System.out.println("main end");
}
}
class Adder implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10000; i++)
Counter.addId();
System.out.println(Thread.currentThread().getName() + " end");
}
}
class Subtracter implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10000; i++)
Counter.subtractId();
System.out.println(Thread.currentThread().getName() + " end");
}
}
class Counter {
private static int id = 0;
public static void addId() {
synchronized (Counter.class) { //同步代码块。获得指定对象的内在锁。这里是获得Counter.class这个对象的内在锁。效率更高(仅必要的代码块进入同步)
id++;
}
}
public static synchronized void subtractId() { //静态同步方法。获得当前对象(Counter.class)的内在锁。
id--;
}
public static int getId() {
return id;
}
}
2. 使用synchronized、wait、notify解决线程间的合作(同步)问题
主程序代码
1个生产者与3个消费者,同时运行,产生了线程的同步问题。
public class MyProducerConsumerTestUpdate {
/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
Repository repo = new Repository();
Thread producer = new Thread(new Producer(repo,1500));
Thread consumer1 = new Thread(new Consumer(repo,500));
Thread consumer2 = new Thread(new Consumer(repo,500));
Thread consumer3 = new Thread(new Consumer(repo,500));
producer.start();
consumer1.start();
consumer2.start();
consumer3.start();
producer.join();
consumer1.join();
consumer2.join();
consumer3.join();
System.out.println("main end! repo中还有 "+repo.size()+"个货物!");
}
}
生产者与消费者代码
class Consumer implements Runnable {
private Repository repo;
private int count;//让Consumer取count次
public Consumer(Repository repo, int count) {
this.repo = repo;
this.count = count;
}
@Override
public void run() {
for (int i = 0; i < count; i++) {
repo.get();//每回都从仓库中取出一个货物
}
System.out.format("取出%d个货物完毕!",count);
}
}
class Producer implements Runnable {
private Repository repo;
private int count; //让Producer放入count次
public Producer(Repository repo, int count) {
this.repo = repo;
this.count = count;
}
@Override
public void run() {
for (int i = 0; i < count; i++) {
repo.put(new String("sth"));// 每回都放入一个新的货物(字符串对象)
}
System.out.format("放入%d个货物完毕!",count);
}
}
仓库代码(重点)注意其中的wait、notify的时机
import java.util.ArrayList;
import java.util.List;
class Repository {// 存放字符串的仓库
private int capacity = 10;//仓库容量默认为10
private List<String> repo = new ArrayList<>();// repo(仓库),最多只能放10个
public synchronized void put(String t) { //同步代码首先要使用synchronized以实现互斥访问。
try {
if (size() == capacity){ //同步问题中,应当将对条件的判断放入循环中,以保证条件确实满足。
System.out.println("仓库已满,请稍等");
wait();
}
repo.add(t);
System.out.println("放了一件货物到repo");
notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void get() {
try {
if (size() == 0) { //这里不能解决问题。同步问题中,应当将对条件的判断放入循环中,以保证条件确实满足。
System.out.println("仓库中无货物,请稍候");
wait();
}
repo.remove(0);
System.out.println("从repo取出一件货物");
notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public int getCapacity(){ //返回仓库容量
return capacity;
}
public synchronized int size(){ //思考:该方法是否应该使用synchronized修饰
return repo.size();
}
}
注意:该代码并未同步解决问题。思考:如果一个生产者一下唤醒多个消费者,或者相反,会出现什么情况?