从线程中取得信息
轮询 主程序无限循环,从子线程取得返回值,直到子线程执行完毕(返回值不为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
回调 子线程执行完成后,调用主线程的方法
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
同步
同步块 java无法阻止其他所有线程使用共享资源的方法,他只能防止对同一对象同步的其他线程使用该共享资源
同步方法
同步的替代方法
1 使用局部变量代替类变量
2 简单类型的方法参数是安全的,因为java通过值传递不是引用传递参数,对象类型的方法参数,如果是final的,也是线程安全的
3 将非线程安全的类,作为一个线程安全的类的私有字段
死锁
防止死锁要避免不必要的线程同步!!
线程调度
抢占与协作 抢占式线程调度器确定线程公平的享用CPU时间,然后暂停此线程,将CPU控制权交给另外的线程。(饥饿问题很难发现)
协作式线程调度器会在CPU控制权交给其他线程前,等待运行中的线程自己暂停。
为了有利于其他线程,一个线程有以下方式可以暂停或指示准备暂停
阻塞 I/O时阻塞、同步其他对象是阻塞。当线程必须停下来,等待他没有的资源,就发生了阻塞。此时线程不会释放任何线程已经拥有的锁。
放弃 Thread.yield()。线程愿意暂停,让其他同等优先级的线程有机会运行
休眠 Thread.sleep()。线程不管有没有其他线程准备运行都会暂停
调用休眠线程的interrupt()方法,可以唤醒该线程,这是线程与Thread对象之间的重要区别之一(线程休眠中,仍然可以调用方法与之交互)唤醒会让休眠线程得到一个InterruptedException
一个通过InterruptedException结束线程的例子
public void run(){
while(true){
try{ Thread.sleep(300000);
}catch(InterruptedException e){ break;}}}
连接线程 Thread.join()。一个线程需要另一个线程的结果,即主线程(调用join()方法的线程)等待被连接的线程(join()方法被调用的线程)结束.
等待一个对象 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();
}
基于优先级的抢占 setPriority()方法
结束 当run()方法返回时,线程将销毁,其他线程就可以接管CPU。
线程池
实现方法
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;
}
分享到:
相关推荐
很好的线程学习资料.。含有部分源代码。
java线程学习笔记
NULL 博文链接:https://ralf-realman.iteye.com/blog/417416
java线程 线程 教程 java线程教程 java线程学习资料 本教程有什么内容? 本教程研究了线程的基础知识— 线程是什么、线程为什么有用以及怎么开始编写使用线程的简单 程序。 我们还将研究更复杂的、使用线程的应用...
里面包含了几个Java线程学习的例子,程序既简单又能让人很快理解线程的工作原理,是初学者不错的选择
Java线程学习好资料,JAVA多线程。
附带JAVA线程源代码,从代码中分析和学习java线程。
java线程学习总结.pdf
JAVA多线程学习,提高JAVA性能,多线程并列. JAVA高级学习内容。
java中多线程下载学习,又新增了断点的实现,可以实现暂停继续下载网络文件的功能
java 线程专题学习, 包含拽取的 javaeye 上的经典教程
对于学习java线程的初学者是很有用的资料,让自己很快的上手,帮助自己学习很快的知识。。。
关于java线程的一些理解。 和大家分享一下
本教程适用于拥有丰富 Java 语言应用知识,但又没有多少多线程或并发性经验的Java 程序员。 学习完本教程之后,您应该可以编写一个使用线程的简单程序。您还应该可以阅读并理解以简单方法使用线程的程序。
电子书相关:包含4个有关JAVA线程的电子书(几乎涵盖全部有关线程的书籍) OReilly.Java.Threads.3rd.Edition.Sep.2004.eBook-DDU Java Thread Programming (Sams) java线程第二版中英文 java线程第二版中英文 ...
本教程适用于拥有丰富Java 语言应用知识,但又没有多少多线程或并发性经验的 Java 程序员。 学习完本教程之后,您应该可以编写一个使用线程的简单程序。您还应该可以阅读并理解以简单方 法使用线程的程序。