java线程并发问题已经看了有些次数了,到头来还是迷迷糊糊,不知所以,今次总结,以其奏效。

首先说说经验教训,以前对知识点只是些零散的记忆,并不涉及到知识体系的形成,只关注其结果并未关注其体系中的知识结构。也好终于算碰到问题,也解决了这些问题。

直接上题,

1.有4个线程,其中两个对变量进行加运算,另两个对变量进行减运算,各100次,然后总进行50次

问题:1.线程在java中实现,继承自那个类,怎么样就能开始一个线程。

java中实现一个线程有两个方法,一个继承Thread类,一个实现Runnable接口(jdk5以后碰到另谈),一般多用第二种。实现Runnable接口必须重写其run()方法,这个也就是线程需要运行的实体。然后调用start()方法开始运行线程

2.怎么实现线程加锁,即保证线程实体操作的原子性?

用sycronized对方法修饰。

public class ChangeNum {
	int number = 0;

	public synchronized void inc() {
		this.number++;
		System.out.println("number inc后的现在值是" + number);
	}

	public synchronized void dec() {
		this.number--;
		System.out.println("number dec后的现在值是" + number);
	}

	class TAdd implements Runnable {
		@Override
		public void run() {
			// TODO Auto-generated method stub
			for (int i = 0; i < 100; i++) {
				inc();
			}
		}

	}

	class TSub implements Runnable {
		@Override
		public void run() {
			// TODO Auto-generated method stub
			for (int i = 0; i < 100; i++) {
				dec();
			}
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		for (int i = 0; i < 2; i++) {
			new Thread(new ChangeNum().new TAdd()).start();
			new Thread(new ChangeNum().new TSub()).start();
		}
	}

}

程序分析:由于要对一个变量进行改变,所以加减线程类都设计成内部类的形式,在run()调用inc()方法,显然在对number进行加减时是不能放弃cpu的,所以要加互斥锁。

问题2:模拟生产--消费者问题

1.wait()方法的含义,与sleep()方法的区别?

wait()方法时object()类的方法,sleep()方法时Thread类的方法,其含义为:当前线程放弃对当前对象的锁并进入睡眠状态

2.notify()方法的含义

通知正在等待的线程可以获得资源,开始运行(昨天看到这儿突然想到线程运行到底是怎样的,java里不是那么多方法可以对其进行改变,他的状态有什么,状态转换又是怎样的,然后总结了一下,待会会写出来) 

/*生产者消费者问题*/
public class ProducerConsumer {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Barsket barsket = new Barsket();
		Producer producer = new Producer(barsket);
		Consumer consumer = new Consumer(barsket);

		Thread t1 = new Thread(producer);
		Thread t2 = new Thread(consumer);
		t1.start();
		t2.start();
	}
}

class ManTou {
	int id;

	public ManTou(int id) {
		// TODO Auto-generated constructor stub
		this.id = id;
	}

	public String toString() {
		return "ManTou" + id;
	}
}

class Barsket {
	int index = 0;
	ManTou[] arrManTou = new ManTou[6];

	public synchronized void push(ManTou mt) {
		while (index == arrManTou.length) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		this.notify();
		arrManTou[index] = mt;
		System.out.println("馒头" + mt.id + "被放入篮子里");
		index++;
	}

	public synchronized ManTou pop() {
		if (index == 0) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		this.notify();
		index--;
		System.out.println("ManTou" + arrManTou[index].id + "被消费了");
		return arrManTou[index];
	}
}

class Producer implements Runnable {
	Barsket barsket = new Barsket();

	public Producer(Barsket barsket) {
		// TODO Auto-generated constructor stub
		this.barsket = barsket;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for (int i = 0; i < 10; i++) {
			ManTou mt = new ManTou(i);
			barsket.push(mt);

			try {
				Thread.sleep((int) (Math.random() * 200));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

class Consumer implements Runnable {
	Barsket barsket = new Barsket();

	public Consumer(Barsket barsket) {
		// TODO Auto-generated constructor stub
		this.barsket = barsket;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for (int i = 0; i < 10; i++) {
			barsket.pop();

			try {
				Thread.sleep((int) (Math.random() * 1000));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

至此,算是对线程有了大概的认识了。下一篇线程状态及其转换