您的位置:首页 > 其它

Concurrency programming Learning notes

2010-06-06 22:32 399 查看
1.线程并非在start以后立即进入running状态,而只是进入ready状态而已。

2.sleep():Thread的静态方法,在哪个thread中调用,则哪个thread睡眠

3.Thread的interrupt方法可以显示中断线程的执行,并抛出InterruptedException异常,故此法甚为暴力,不宜使用。

通常中断线程的方式是改变循环代码的执行条件。更为暴力的是stop()方法,它直接导致线程被kill

4.Thread还有其他的static方法诸如join()及yield()

join(): //导致调用该方法的thread执行完毕

yield(); // 让出时间片给其他线程,进入等待队列。

5.以下摘自网络:

关于Java的线程,初学或者接触不深的大概也能知道一些基本概念,同时又会很迷惑线程到底是怎么回事?如果有人认为自己已经懂了不妨来回答下面的问题:

a. A对象实现Runnable接口,A.start()运行后所谓的线程对象是谁?是A么?

b. 线程的wait()、notify()方法到底是做什么时候用的,什么时候用?

c. 为什么线程的suspend方法会被标注过时,不推荐再使用,线程还能挂起么?

d. 为了同步我们会对线程方法声明Synchronized来加锁在对象上,那么如果父类的f()方法加了Synchronized,子类重写f()方法必须也加Synchronized么?如果子类的f()方法重写时声明Synchronized并调用super.f(),那么子类对象上到底有几把锁呢?会因为竞争产生死锁么?

呵呵,各位能回答上来几道呢?如果这些都能答上来,说明对线程的概念还是满清晰的,虽说还远远不能算精通。笔者这里一一做回答,碍于篇幅的原因,笔者尽量说得简介一点,如果大家有疑惑的欢迎一起讨论。

首先第一点,线程跟对象完全是两回事,虽然我们也常说线程对象。但当你用run()和start()来启动一个线程之后,线程其实跟这个继承了 Thread或实现了Runnable的对象已经没有关系了,对象只能算内存中可用资源而对象的方法只能算内存正文区可以执行的代码段而已。既然是资源和代码段,另外一个线程当然也可以去访问,main函数执行就至少会启动两个线程,一个我们称之为主线程,还一个是垃圾收集器的线程,主线程结束就意味着程序结束,可垃圾收集器线程很可能正在工作。

第二点,wait()和sleep()类似,都是让线程处于阻塞状态暂停一段时间,不同之处在于wait会释放当前线程占有的所有的锁,而 sleep不会。我们知道获得锁的唯一方法是进入了Synchronized保护代码段,所以大家会发现只有Synchronized方法中才会出现 wait,直接写会给警告没有获得当前对象的锁。所以notify跟wait配合使用,notify会重新把锁还给阻塞的线程重而使其继续执行,当有多个对象wait了,notify不能确定唤醒哪一个,必经锁只有一把,所以一般用notifyAll()来让它们自己根据优先级等竞争那唯一的一把锁,竞争到的线程执行,其他线程只要继续wait。

从前Java允许在一个线程之外把线程挂起,即调用suspend方法,这样的操作是极不安全的。根据面向对象的思想每个对象必须对自己的行为负责,而对自己的权力进行封装。如果任何外步对象都能使线程被挂起而阻塞的话,程序往往会出现混乱导致崩溃,所以这样的方法自然是被毙掉了啦。

最后一个问题比较有意思,首先回答的是子类重写f()方法可以加Synchronized也可以不加,如果加了而且还内部调用了super.f ()的话理论上是应该对同一对象加两把锁的,因为每次调用Synchronized方法都要加一把,调用子类的f首先就加了一把,进入方法内部调用父类的 f又要加一把,加两把不是互斥的么?那么调父类f加锁不就必须永远等待已经加的锁释放而造成死锁么?实际上是不会的,这个机制叫重进入,当父类的f方法试图在本对象上再加一把锁的时候,因为当前线程拥有这个对象的锁,也可以理解为开启它的钥匙,所以同一个线程在同一对象上还没释放之前加第二次锁是不会出问题的,这个锁其实根本就没有加,它有了钥匙,不管加几把还是可以进入锁保护的代码段,畅通无阻,所以叫重进入,我们可以简单认为第二把锁没有加上去。

总而言之,Synchronized的本质是不让其他线程在同一对象上再加一把锁。

6. wait()和sleep():

1) wait()通常只在sychronized方法/代码中被调用,用以释放锁,sleep不然

2) wait()方法属于object,而sleep则属于Thread,注意Runnable接口中只有run方法

3) this.wait()虽然是被对象所调用,但其含义是访问该对象的线程wait。

4) wait和notify/notifyAll一定是一一对应的,否则必然会存在死锁。

7. Producer and Consumer:
public class ProducerConsumer {
public static void main(String[] args) {
SyncStack ss = new SyncStack();
Producer p = new Producer(ss);
Consumer c = new Consumer(ss);
new Thread(p).start();
new Thread(p).start();
new Thread(p).start();
new Thread(c).start();
}
}
class Bread {
int id;
Bread(int id) {
this.id = id;
}
public String toString() {
return "Bread : " + id;
}
}
class SyncStack {
int index = 0;
Bread[] arr = new Bread[6];

public synchronized void push(Bread bread) {
while(index == arr.length) { // use while rather than if,
try {                      // or the the loop will exit if InterruptedException occured
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();
arr[index] = bread;
index ++;
}

public synchronized Bread pop() {
while(index == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();
index--;
return arr[index];
}
}
class Producer implements Runnable {
SyncStack ss = null;
Producer(SyncStack ss) {
this.ss = ss;
}

public void run() {
for(int i=0; i<20; i++) {
Bread bread = new Bread(i);
ss.push(bread);
System.out.println("produced:" + bread);
try {
Thread.sleep((int)(Math.random() * 200));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
SyncStack ss = null;
Consumer(SyncStack ss) {
this.ss = ss;
}

public void run() {
for(int i=0; i<20; i++) {
Bread bread = ss.pop();
System.out.println("consumed: " + bread);
try {
Thread.sleep((int)(Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: