从线程中取得信息
轮询 主程序无限循环,从子线程取得返回值,直到子线程执行完毕(返回值不为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线程学习知识点 #### 一、Java线程概览 - **定义与作用**:线程是在程序中独立且并发执行的路径。在Java中,线程被设计为语言的一部分,而不是作为操作系统的底层工具。每个Java程序至少包含一个主线程,在...
在Java编程语言中,线程是程序执行的基本单元,它允许程序并发地...同时,"Java线程学习和总结.files"目录下的文件可能是与文章相关的辅助资料,例如代码示例或图片。建议结合这些资料一起学习,以获得更全面的知识。
本资源"JAVA线程学习(源代码)"提供了关于Java线程的源代码示例,帮助我们深入理解和实践线程的使用。 首先,我们要理解Java中的线程模型。Java线程由`java.lang.Thread`类或`java.util.concurrent.Executor`框架来...
Java 线程学习笔记 Java 线程创建有两种方法: 1. 继承 Thread 类,重写 run 方法:通过继承 Thread 类并重写 run 方法来创建线程,这种方法可以使线程具有自己的执行逻辑。 2. 实现 Runnable 接口:通过实现 ...
### Java线程学习教程知识点详解 #### 一、教程概览 - **适用人群**: 本教程主要面向那些已经熟练掌握了Java语言基本语法和应用,但对于多线程和并发编程经验较少的Java开发者。 - **目标**: 学习者通过本教程的...
在"java线程学习一4"这个主题中,我们将会深入探讨Java中的多线程概念,以及如何通过源码理解和使用相关工具进行线程管理。 首先,我们需要理解Java中的线程创建方式。Java提供了两种主要的线程创建方法:继承...
### Java线程学习知识点 #### 一、线程的基本概念与创建 - **线程**:线程是程序执行流的最小单元。一个标准的Java应用程序至少有一个线程,即main线程。Java中线程的创建主要有两种方式:继承`Thread`类或者实现`...
通过学习以上知识点,初学者可以对Java线程有基本的理解,逐步掌握并发编程的核心技能。实践中的线程例子将有助于巩固理论知识,加深对线程工作原理的把握。在学习过程中,不断编写和调试多线程程序,是提升技能的...
本文将深入探讨Java线程的学习要点,帮助你提升在多线程环境下的编程能力。 首先,我们要明白线程的基本概念。线程是操作系统分配CPU时间的基本单元,一个进程中可以有多个线程同时执行任务,这使得程序可以在同一...
本专题资料聚焦于Java线程的学习,包括从基础到进阶的各种知识点。 1. **线程创建方式**:Java提供了两种创建线程的方式,一是通过继承Thread类,重写run()方法;二是实现Runnable接口,然后创建Thread对象并传入...
总的来说,Java多线程学习涵盖了线程的创建、同步、通信、调度以及异常处理等多个方面,深入理解和掌握这些知识点对于提升Java程序的性能和复杂性至关重要。通过阅读提供的"Java多线程.pdf"文档,你可以进一步了解和...
java中多线程下载学习,又新增了断点的实现,可以实现暂停继续下载网络文件的功能
Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java...
对于学习java线程的初学者是很有用的资料,让自己很快的上手,帮助自己学习很快的知识。。。