前言:多线程只能用thread中的start()方法调用。start()也就相当于操作系统的就绪状态
执行run()方法,相当于有了时间片,cpu可以处理你的的事情
线程同步问题一般将带有synchronized的方法封装于一个信息资源类中。唤醒方法采用柔和方式,信号量机制。有等待wait(),操作完成后要有唤醒notifyAll()。重要的是资源处理完毕一定要记得改变信号。这是很容易犯错的地方。在强调一边,记得改变信号然后再唤醒。
进行多线程问题模拟时要加入sleep(),用来模拟延迟。延迟才能体现实际生产出现的问题。
volatile关键字并不是用来处理同步问题的,请注意这一点。
还有一点很重要的是一般来说如果限定执行次数,因为线程切换问题,资源的实际操作次数和实际次数可能会不一样。
例如:
按原计划生产15台电脑,生产15台,消费15台,生产一台的同时消费完一台才可以进行下一次生产。但是,有可能2次时间片都是给了生产者。你选择线程循环15次,此时就是错误的。正确的方式是将10台电脑做为计数器,实际生产完一台,消费完一台,计数器才减一。另外需要有一个标志,生产标志或者消费标志。当是生产标志时才可以进行生产。
示例中也并没有加入延迟。但加入延迟并不影响。
//以下实为错误示例,不过确是解决了线程同步问题。但执行次数错误
class LxComputer{
private static int count=0; //表示生产的个数
private String name; //电脑名字
private double price;//电脑价值
public LxComputer(String name, double price) {
this.name = name;
this.price = price;
count++;
}
@Override
public String toString() {
return "第"+count+"台Computer [name=" + name + ", price=" + price + "]";
}
}
class ComputerResources{
private LxComputer lxcom;
public synchronized void make(){
if(lxcom!=null){//已经生产过了,需要等待消费
try {
super.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{//没生产过,开始生产电脑
System.out.println("开始生产电脑");
lxcom=new LxComputer("联想电脑",555);
System.out.println("生产电脑完毕");
super.notifyAll();
}
}
public synchronized void get(){
if(lxcom==null){//还没生产,需要等待生产
try {
super.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{//生产过了,取走电脑
System.out.println("正在取走电脑");
System.out.println(lxcom.toString());
lxcom=null;
System.out.println("取走完毕");
super.notifyAll();
}
}
}
class LxComProduce implements Runnable{
private ComputerResources comre;
public LxComProduce(ComputerResources comre){
this.comre=comre;
}
@Override
public void run() {
for(int i=0;i<15;i++){
System.out.println(Thread.currentThread().getName());
this.comre.make();
}
}
}
class LxComConsumer implements Runnable{
private ComputerResources crs;
public LxComConsumer(ComputerResources crs){
this.crs=crs;
}
@Override
public void run() {
for(int i=0;i<15;i++){
System.out.println(Thread.currentThread().getName());
this.crs.get();
}
}
}
public class MyComputer {
public static void main(String args[]){
ComputerResources crs=new ComputerResources() ;
new Thread (new LxComConsumer(crs),"消费电脑").start();
new Thread (new LxComProduce(crs),"生成电脑").start();
}
}