多线程的同步控制
有时线程之间彼此不独立、需要同步
线程间的互斥
- 同时运行的几个线程需要共享一些数据
- 共享的数据在某一时刻只允许一个线程对其进行操作
“生产者/消费者”问题
- 假设有一个线程负责往数据区写数据,另一个线程从同一数据区中读数据,两个线程可以并行执行
- 如果数据区已满,生产者要等消费者取走一些数据后才能再写
- 当数据区空时,消费者要等生产者写入一些数据后再取
用两个线程模拟存票、取票过程
- 假定开始售票处并没有票,一个线程往里存票,另一个线程则往出卖票
- 新键一个票类对象,让存票和售票线程都访问它。本例采用两个线程共享同一数据对象来实现同一份数据的操作
class Tickets{
int number = 0; //票号
int size; //总票数
boolean available = false; //表示目前是否有票可售
public Tickets(int size) { //构造函数,传入总票数参数
this.size = size;
}
}
class Producer extends Thread{
Tickets t = null;
public Producer(Tickets t) {
this.t = t;
}
public void run() {
while(t.number < t.size) {
System.out.println("Producer puts ticket "+(++t.number));
t.available = true;
}
}
}
class Consumer extends Thread{
Tickets t = null;
int i = 0;
public Consumer(Tickets t) {
this.t = t;
}
public void run() {
while(i < t.size) {
if(t.available == true&&i <= t.number)
System.out.println("Consumer buys ticket "+(++i));
if(i == t.number) //现有的票卖完了
t.available = false;
}
}
}
public class ProducerAndConsumer {
public static void main(String[] args) {
Tickets t = new Tickets(10); //建立票对象,票总数是10
new Consumer(t).start(); //开始卖票线程
new Producer(t).start(); //开始存票线程
}
}
运行结果
通过两个线程操作同一个票类对象,实现数据共享的目的
线程同步
- 互斥:许多线程在同一个共享数据上操作而互不干扰,同一时刻只能有一个线程访问该共享数据。因此有些方法或程序段在同一时刻只能被一个线程执行,称之为监视区
-协作:多个线程可以有条件的同时操作共享数据。执行监视区代码的线程在条件满足的情况下允许其他线程进入监视区
线程同步的方法:
把synchronized当作函数修饰符
public synchornized (static) void aMethod(){
//do something
}
synchronized锁定的那个对象
- 它锁定的是调用这个同步方法对象
- 当一个对象p1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果
- 但是这个对象所属的Class所产生的另一个对象p2却可以任意调用这个被加了synchornized关键字的方法
静态同步synchornized方法与synchornized(class) 代码块持有的锁一样,都是Class锁,Class锁对对象的所有实例起作用
java中万物皆对象,实例是对象的一种
- 比如Person p = new Person 这里是实例对象
- 比如Class p = Person.class 这里是类对象
下面来一个栗子:
class J_Experiment{
public static void mb_sleep(long millis) {
try {
Thread.sleep(millis);
}
catch(InterruptedException e) {
System.err.println("异常InterruptedException: "+e);
e.printStackTrace();
}
} //方法try/mb_sleep结束
public static synchronized void m_methodStatic(int id) {
System.out.println("线程" + id + "进入--静--态同步方法");
mb_sleep(1000);
System.out.println("线程" + id + "离开--静--态同步方法");
}//方法m_methodStatic结束
public synchronized void m_methodSynchronized(int id) {
System.out.println("线程" + id + "进入::非静::态同步方法");
mb_sleep(1000);
System.out.println("线程" + id + "离开::非静::态同步方法");
}//方法m_methodSynchroized结束
public void m_method(int id) {
System.out.println("线程" + id + "进入##非静态非同步方法");
mb_sleep(1000);
System.out.println("线程" + id + "离开##非静态非同步方法");
}//方法m_method结束-类J-Experiment结束
}
public class SynchronizationStaticNo1 extends Thread {
public int m_ID;
public J_Experiment m_data;
SynchronizationStaticNo1(int id){
m_ID = id;
} //J_SynchronizedStatic构造方案结束
public void run() {
System.out.println("运行线程:" + m_ID);
m_data.m_methodSynchronized(m_ID);
m_data.m_methodStatic(m_ID);
m_data.m_method(m_ID);
System.out.println("结束线程:" + m_ID);
} //方法run结束
public static void main(String[] args) {
// TODO Auto-generated method stub
int n = 2;
J_Experiment d4 = new J_Experiment();
SynchronizationStaticNo1 t4 = new SynchronizationStaticNo1(4);
t4.m_data = d4;
t4.start();
J_Experiment d5 = new J_Experiment();
SynchronizationStaticNo1 t5 = new SynchronizationStaticNo1(5);
t5.m_data = d5;
t5.start();
System.out.println("方法main结束");
}
}
运行结果: