[size=large][b]从线程中取得信息[/b][/size]
[b]轮询 [/b] 主程序无限循环,从子线程取得返回值,直到子线程执行完毕(返回值不为0)
[b]回调[/b] 子线程执行完成后,调用主线程的方法
[size=large][b]同步[/b] [/size]
[b]同步块[/b] java无法阻止其他所有线程使用共享资源的方法,他只能防止对同一对象同步的其他线程使用该共享资源
[b]同步方法[/b]
[b]同步的替代方法[/b]
1 使用局部变量代替类变量
2 简单类型的方法参数是安全的,因为java通过值传递不是引用传递参数,对象类型的方法参数,如果是final的,也是线程安全的
3 将非线程安全的类,作为一个线程安全的类的私有字段
[size=large][b]死锁[/b][/size]
防止死锁要避免不必要的线程同步!!
[size=large][b]线程调度[/b][/size]
[b]抢占与协作[/b] 抢占式线程调度器确定线程公平的享用CPU时间,然后暂停此线程,将CPU控制权交给另外的线程。(饥饿问题很难发现)
协作式线程调度器会在CPU控制权交给其他线程前,等待运行中的线程自己暂停。
为了有利于其他线程,一个线程有以下方式可以暂停或指示准备暂停
[b]阻塞[/b] I/O时阻塞、同步其他对象是阻塞。当线程必须停下来,等待他没有的资源,就发生了阻塞。此时线程不会释放任何线程已经拥有的锁。
[b]放弃 [/b] Thread.yield()。线程愿意暂停,让其他同等优先级的线程有机会运行
[b]休眠 [/b] Thread.sleep()。线程不管有没有其他线程准备运行都会暂停
调用休眠线程的interrupt()方法,可以唤醒该线程,这是线程与Thread对象之间的重要区别之一(线程休眠中,仍然可以调用方法与之交互)唤醒会让休眠线程得到一个InterruptedException
一个通过InterruptedException结束线程的例子
[b]连接线程 [/b] Thread.join()。一个线程需要另一个线程的结果,即主线程(调用join()方法的线程)等待被连接的线程(join()方法被调用的线程)结束.
[b]等待一个对象[/b] Object.wait()。等待用于暂停执行,直到一个对象或资源达到某种状态,连接则用于暂停执行,知道一个线程结束。在等待时,他会释放此对象的锁并暂停(但不是他拥有的任何其他对象的锁),直到得到其他线程通知notify()或时间到期、线程被中断interrupt()。
一旦等待线程得到通知,他就试图重新获得所等待对象的锁,如果成功,就继续执行紧接着wait()调用后的语句,如果失败,他就会阻塞与此对象,直到可以得到锁。
[b]基于优先级的抢占[/b] setPriority()方法
[b]结束[/b] 当run()方法返回时,线程将销毁,其他线程就可以接管CPU。
[size=large][b]线程池[/b][/size]
实现方法
1 第一次创建池时,分配固定数量的线程,当池为空时,所有线程都在等待,当向池添加一项任务时,所有等待的线程都得到通知。当一个线程结束其分配的任务时,它再回到池中等待新任务。
2 将线程本身放在池中,让主程序从池中取出线程,为其分配任务。每个线程结束后返回池中。
一个例子,多线程压缩文件
[b]轮询 [/b] 主程序无限循环,从子线程取得返回值,直到子线程执行完毕(返回值不为0)
public class ReturnThread extends Thread {
private int time;
private int result;
public ReturnThread(int time) {
this.time = time;
}
public void run() {
try {
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
result = time;
}
public int getResult() {
return result;
}
}
public class ReturnThreadShell {
public static void main(String[] args) {
Random r = new Random(47);
ReturnThread[] threads = new ReturnThread[5];
for (int i = 0; i < 5; i++) {
int time = r.nextInt(10);
ReturnThread thread = new ReturnThread(time);
threads[i] = thread;
thread.start();
}
for (int i = 0; i < threads.length; i++) {
while (true) {
int rslt = threads[i].getResult();
if (rslt != 0) {
System.out.println("thread " + i + "
is finish. return value is " + rslt);
break;
}
}
}
}
}
//thread 0 is finish. return value is 8
//thread 1 is finish. return value is 5
//thread 2 is finish. return value is 3
//thread 3 is finish. return value is 1
//thread 4 is finish. return value is 1
[b]回调[/b] 子线程执行完成后,调用主线程的方法
public class CallbackThread extends Thread {
private int time;
private CallbackThreadShell callback;
public CallbackThread(int time, CallbackThreadShell callback) {
this.time = time;
this.callback = callback;
}
public void run() {
try {
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
callback.receiveResult(time, callback.threadId);
}
}
public class CallbackThreadShell {
private int time;
protected int threadId;
public CallbackThreadShell(int time, int threadId) {
this.time = time;
this.threadId = threadId;
}
public void runThread() {
CallbackThread thread = new CallbackThread(time, this);
thread.start();
}
public void receiveResult(int result, int threadId) {
System.out.println("thread " + threadId
+ " is finish. return value is " + result);
}
public static void main(String[] args) {
Random r = new Random(47);
for (int i = 0; i < 5; i++) {
CallbackThreadShell shell = new CallbackThreadShell(r.nextInt(10), i);
shell.runThread();
}
}
}
//thread 3 is finish. return value is 1
//thread 4 is finish. return value is 1
//thread 2 is finish. return value is 3
//thread 1 is finish. return value is 5
//thread 0 is finish. return value is 8
[size=large][b]同步[/b] [/size]
[b]同步块[/b] java无法阻止其他所有线程使用共享资源的方法,他只能防止对同一对象同步的其他线程使用该共享资源
[b]同步方法[/b]
[b]同步的替代方法[/b]
1 使用局部变量代替类变量
2 简单类型的方法参数是安全的,因为java通过值传递不是引用传递参数,对象类型的方法参数,如果是final的,也是线程安全的
3 将非线程安全的类,作为一个线程安全的类的私有字段
[size=large][b]死锁[/b][/size]
防止死锁要避免不必要的线程同步!!
[size=large][b]线程调度[/b][/size]
[b]抢占与协作[/b] 抢占式线程调度器确定线程公平的享用CPU时间,然后暂停此线程,将CPU控制权交给另外的线程。(饥饿问题很难发现)
协作式线程调度器会在CPU控制权交给其他线程前,等待运行中的线程自己暂停。
为了有利于其他线程,一个线程有以下方式可以暂停或指示准备暂停
[b]阻塞[/b] I/O时阻塞、同步其他对象是阻塞。当线程必须停下来,等待他没有的资源,就发生了阻塞。此时线程不会释放任何线程已经拥有的锁。
[b]放弃 [/b] Thread.yield()。线程愿意暂停,让其他同等优先级的线程有机会运行
[b]休眠 [/b] Thread.sleep()。线程不管有没有其他线程准备运行都会暂停
调用休眠线程的interrupt()方法,可以唤醒该线程,这是线程与Thread对象之间的重要区别之一(线程休眠中,仍然可以调用方法与之交互)唤醒会让休眠线程得到一个InterruptedException
一个通过InterruptedException结束线程的例子
public void run(){
while(true){
try{ Thread.sleep(300000);
}catch(InterruptedException e){ break;}}}
[b]连接线程 [/b] Thread.join()。一个线程需要另一个线程的结果,即主线程(调用join()方法的线程)等待被连接的线程(join()方法被调用的线程)结束.
[b]等待一个对象[/b] Object.wait()。等待用于暂停执行,直到一个对象或资源达到某种状态,连接则用于暂停执行,知道一个线程结束。在等待时,他会释放此对象的锁并暂停(但不是他拥有的任何其他对象的锁),直到得到其他线程通知notify()或时间到期、线程被中断interrupt()。
一旦等待线程得到通知,他就试图重新获得所等待对象的锁,如果成功,就继续执行紧接着wait()调用后的语句,如果失败,他就会阻塞与此对象,直到可以得到锁。
while (pool.isEmpty()) {
try {
pool.wait();
// 收到通知时,停止等待,执行之后的内容
// 必须pool.isEmpty(),因为我们不知道处理完成后,pool中是否仍有内容
} catch (InterruptedException ex) {}
}
// 取得一个连接,处理这一项。。。
connection = (Socket) pool.remove(0);
synchronized (pool) {
pool.add(pool.size(), request);
pool.notifyAll();
}
[b]基于优先级的抢占[/b] setPriority()方法
[b]结束[/b] 当run()方法返回时,线程将销毁,其他线程就可以接管CPU。
[size=large][b]线程池[/b][/size]
实现方法
1 第一次创建池时,分配固定数量的线程,当池为空时,所有线程都在等待,当向池添加一项任务时,所有等待的线程都得到通知。当一个线程结束其分配的任务时,它再回到池中等待新任务。
2 将线程本身放在池中,让主程序从池中取出线程,为其分配任务。每个线程结束后返回池中。
一个例子,多线程压缩文件
public class GZipThread extends Thread {
private List pool;
private static int filesCompressed = 0;
public GZipThread(List pool) {
this.pool = pool;
}
private static synchronized void incrementFilesCompressed() {
filesCompressed++;
System.out.println(filesCompressed);
}
public void run() {
while (filesCompressed != GZipAllFiles.getNumberOfFilesToBeCompressed()) {
File input = null;
synchronized (pool) {
while (pool.isEmpty()) {
if (filesCompressed == GZipAllFiles.getNumberOfFilesToBeCompressed()) {
System.out.println("Thread ending");
return;
}
try {
pool.wait();
} catch (InterruptedException ex) {
}
}
input = (File) pool.remove(pool.size() - 1);
incrementFilesCompressed();
}
// don't compress an already compressed file
if (!input.getName().endsWith(".gz")) {
try {
InputStream in = new FileInputStream(input);
in = new BufferedInputStream(in);
File output = new File(input.getParent(), input.getName() + ".gz");
if (!output.exists()) { // Don't overwrite an existing file
OutputStream out = new FileOutputStream(output);
out = new GZIPOutputStream(out);
out = new BufferedOutputStream(out);
int b;
while ((b = in.read()) != -1)
out.write(b);
out.flush();
out.close();
in.close();
}
} catch (IOException ex) {
System.err.println(ex);
}
} // end if
} // end while
} // end run
} // end ZipThread
public class GZipAllFiles {
public final static int THREAD_COUNT = 4;
private static int filesToBeCompressed = -1;
public static void main(String[] args) {
Vector pool = new Vector();
GZipThread[] threads = new GZipThread[THREAD_COUNT];
for (int i = 0; i < threads.length; i++) {
threads[i] = new GZipThread(pool);
threads[i].start();
}
int totalFiles = 0;
for (int i = 0; i < args.length; i++) {
File f = new File(args[i]);
if (f.exists()) {
if (f.isDirectory()) {
File[] files = f.listFiles();
for (int j = 0; j < files.length; j++) {
// 不递归文件夹
if (!files[j].isDirectory()) {
totalFiles++;
synchronized (pool) {
pool.add(0, files[j]);
pool.notifyAll();
}
}
}
} else {
totalFiles++;
synchronized (pool) {
pool.add(0, f);
pool.notifyAll();
}
}
} // end if
} // end for
filesToBeCompressed = totalFiles;
System.out.println("totalFiles " + filesToBeCompressed);
// 让等待线程知道,没有更多的文件会加到池中了
// 如果需要压缩文件很少,有可能线程启动了,但没有需要压缩的文件
for (int i = 0; i < threads.length; i++) {
threads[i].interrupt();
}
}
public static int getNumberOfFilesToBeCompressed() {
return filesToBeCompressed;
}