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();
}
}
}
}
至此,算是对线程有了大概的认识了。下一篇线程状态及其转换