标签:nano bsp mon 应该 理由 监视 同步锁 线程池 self
使用java.lang.Thread类或者java.lang.Runnable接口编写代码来定义、实例化和启动新线程。
一个Thread类实例只是一个对象,像Java中的任何其他对象一样,具有变量和方法,生死于堆上。
Java中,每个线程都有一个调用栈,即使不在程序中创建任何新的线程,线程也在后台运行着。
一个Java应用总是从main()方法开始运行,mian()方法运行在一个线程内,它被称为主线程。
一旦创建一个新的线程,就产生一个新的调用栈。
线程总体分两类:用户线程和守候线程。
守护线程与用户线程的区别是:
守护线程就是main同生共死,当main退出,它将终止,而普通线程是在任务执行结束才停止。守护线程则是用来服务用户线程的,如果没有其他用户线程在运行,那么就没有可服务对象,也就没有理由继续下去。
Java虚拟机在它所有非守护线程已经离开后自动离开。
但是daemon Thread实际应用在那里呢?举个例子,web服务器中的Servlet,容器启动时后台初始化一个服务线程,即调度线程,负责处理http请求,然后每个请求过来调度线程从线程池中取出一个工作者线程来处理该请求,从而实现并发控制的目的。
线程是进程中的最小执行单元。也就是说,进程包含线程,一个进程可以完成多个任务,每个任务就可以看作是一个线程。
那什么又是进程呢。
持有资源和线程的是进程。
使用线程的目的是辅助写出CPU最大利用率的高效程序,使环境异步。
class DoSomething implements Runnable {
private String name;
public DoSomething(String name) {
this.name = name;
}
public void run() {
for (int i = 0; i < 5; i++) {
for (long k = 0; k < 10; k++)
System.out.println(name + ": " + i);
}
}
}
public class TestRunnable {
public static void main(String[] args) {
DoSomething ds1 = new DoSomething("阿三");
DoSomething ds2 = new DoSomething("李四");
Thread t1 = new Thread(ds1);
Thread t2 = new Thread(ds2);
t1.start();
t2.start();
}
}
/**
* 测试扩展Thread类实现的多线程程序
*/
public class TestThread extends Thread{
public TestThread(String name) {
super(name);
}
public void run() {
for(int i = 0;i<5;i++){
for(long k= 0; k <10;k++)
System.out.println(this.getName()+" :"+i);
}
}
public static void main(String[] args) {
Thread t1 = new TestThread("阿三");
Thread t2 = new TestThread("李四");
t1.start();
t2.start();
}
}
对于上面的多线程程序代码来说,输出的结果是不确定的。其中的一条语句for(long k= 0; k <10;k++);是用来模拟一个非常耗时的操作的。
在线程的Thread对象上调用start()方法,而不是run()或者别的方法。
在调用start()方法之前:线程处于新状态中,新状态指有一个Thread对象,但还没有一个真正的线程。
在调用start()方法之后:发生了一系列复杂的事情
启动新的执行线程(具有新的调用栈);
该线程从新状态转移到可运行状态;
当该线程获得机会执行时,其目标run()方法将运行。
注意:对Java来说,run()方法没有任何特别之处。像main()方法一样,它只是新线程知道调用的方法名称(和签名)。因此,在Runnable上或者Thread上调用run方法是合法的。但并不启动新的线程。
线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。
需要完成两个操作:
当然,同步方法也可以改写为非同步方法,但功能完全一样的,例如:
public synchronized int getX() {
return x++;
}
与
public int getX() {
synchronized (this) {
return x;
}
}
效果是完全一样的。
先看这三个方法
void notify()
唤醒在此对象监视器上等待的单个线程。
void notifyAll()
唤醒在此对象监视器上等待的所有线程。
void wait()
导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法。
当然,wait()还有另外两个重载方法:
void wait(long timeout)
导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法,或者超过指定的时间量。
void wait(long timeout, int nanos)
导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。
以上这些方法是帮助线程传递线程关心的时间状态。
关于等待/通知,要记住的关键点是:
必须从同步环境内调用wait()、notify()、notifyAll()方法。线程不能调用对象上等待或通知的方法,除非它拥有那个对象的锁。
wait()、notify()、notifyAll()都是Object的实例方法。与每个对象具有锁一样,每个对象可以有一个线程列表,他们等待来自该信号(通知)。线程通过执行对象上的wait()方法获得这个等待列表。从那时候起,它不再执行任何其他指令,直到调用对象的notify()方法为止。如果多个线程在同一个对象上等待,则将只选择一个线程(不保证以何种顺序)继续执行。如果没有线程等待,则不采取任何特殊操作。
sleep();不放锁,这是它与wait的主要区别。
public class MyThreadPrinter implements Runnable {
private String name;
private Object prev;
private Object self;
private MyThreadPrinter2(String name, Object prev, Object self) {
this.name = name;
this.prev = prev;
this.self = self;
}
@Override
public void run() {
int count = 10;
while (count > 0) {
synchronized (prev) {
synchronized (self) {
System.out.print(name);
count--;
self.notify();
}
try {
prev.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws Exception {
Object a = new Object();
Object b = new Object();
Object c = new Object();
MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a);
MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b);
MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c);
new Thread(pa).start();
new Thread(pb).start();
new Thread(pc).start(); }
}
标签:nano bsp mon 应该 理由 监视 同步锁 线程池 self
原文地址:http://www.cnblogs.com/sargeles/p/6667002.html