线程安全问题:由于多线程同时 *** 作共享的数据结构,可能会导致数据竞争和不一致的结果。需要使用同步机制(如锁、信号量、原子变量等)来保证线程安全。
2 死锁问题:如果多个线程相互等待对方释放锁,就会形成死锁。需要避免出现这种情况,可以使用避免死锁的算法或者设计合理的锁竞争策略。
3 内存泄漏问题:如果程序没有正确地释放内存,就会导致内存泄漏。在异步堆栈实验中,如果不及时清理已经完成的任务,就可能导致内存泄漏。
4 性能问题:多线程异步堆栈实验中,线程数量和任务数量的平衡会影响程序的性能。如果线程数量过多,会导致线程切换的开销增大,从而影响程序的性能。
5 异常处理问题:在异步堆栈实验中,如果任务出现异常,需要及时捕获并处理,否则可能会导致程序崩溃。
6 调试问题:多线程异步堆栈实验中,由于多个线程同时执行,调试会变得困难。需要使用合适的调试工具和技巧,例如断点调试、日志输出等。
1、继承Thread,然后生成对象2、用类A实现runable接口,然后用你实现runnable的类A,生成Thread对象 Thread(A对象);
API 上说明如下:
创建新执行线程有两种方法。一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例。例如,计算大于某一规定值的质数的线程可以写成:
class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { thisminPrime = minPrime; } public void run() { // compute primes larger than minPrime } }
然后,下列代码会创建并启动一个线程:
PrimeThread p = new PrimeThread(143); pstart();
创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。采用这种风格的同一个例子如下所示:
implements Runnable { long minPrime; PrimeRun(long minPrime) { thisminPrime = minPrime; } public void run() { // compute primes larger than minPrime } }
然后,下列代码会创建并启动一个线程:
rimeRun p = new PrimeRun(143); new Thread(p)start();1、继承Thread类实现多线程
继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。例如:
[java] view plain copy
public class MyThread extends Thread {
public void run() {
Systemoutprintln("MyThreadrun()");
}
}
在合适的地方启动线程如下:
[java] view plain copy
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
myThread1start();
myThread2start();
2、实现Runnable接口方式实现多线程
如果自己的类已经extends另一个类,就无法直接extends Thread,此时,必须实现一个Runnable接口,如下:
[java] view plain copy
public class MyThread extends OtherClass implements Runnable {
public void run() {
Systemoutprintln("MyThreadrun()");
}
}
为了启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread实例:
[java] view plain copy
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread);
threadstart();
事实上,当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用targetrun(),参考JDK源代码:
[java] view plain copy
public void run() {
if (target != null) {
targetrun();
}
}
3、使用ExecutorService、Callable、Future实现有返回结果的多线程
ExecutorService、Callable、Future这个对象实际上都是属于Executor框架中的功能类。想要详细了解Executor框架的可以访问>Java线程:线程的交互
SCJP5学习笔记
线程交互是比较复杂的问题,SCJP要求不很基础:给定一个场景,编写代码来恰当使用等待、通知和通知所有线程。
一、线程交互的基础知识
SCJP所要求的线程交互知识点需要从javalangObject的类的三个方法来学习:
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()方法为止。如果多个线程在同一个对象上等待,则将只选择一个线程(不保证以何种顺序)继续执行。如果没有线程等待,则不采取任何特殊 *** 作。
下面看个例子就明白了:
/
计算输出其他线程锁计算的数据
@author leizhimin 2008-9-15 13:20:38
/
public class ThreadA {
public static void main(String[] args) {
ThreadB b = new ThreadB();
//启动计算线程
bstart();
//线程A拥有b对象上的锁。线程为了调用wait()或notify()方法,该线程必须是那个对象锁的拥有者
synchronized (b) {
try {
Systemoutprintln("等待对象b完成计算。。。");
//当前线程A等待
bwait();
} catch (InterruptedException e) {
eprintStackTrace();
}
Systemoutprintln("b对象计算的总和是:" + btotal);
}
}
}
/
计算1+2+3 +100的和
@author leizhimin 2008-9-15 13:20:49
/
public class ThreadB extends Thread {
int total;
public void run() {
synchronized (this) {
for (int i = 0; i < 101; i++) {
total += i;
}
//(完成计算了)唤醒在此对象监视器上等待的单个线程,在本例中线程A被唤醒
notify();
}
}
}
等待对象b完成计算。。。
b对象计算的总和是:5050
Process finished with exit code 0
千万注意:
当在对象上调用wait()方法时,执行该代码的线程立即放弃它在对象上的锁。然而调用notify()时,并不意味着这时线程会放弃其锁。如果线程荣然在完成同步代码,则线程在移出之前不会放弃锁。因此,只要调用notify()并不意味着这时该锁变得可用。
二、多个线程在等待一个对象锁时候使用notifyAll()
在多数情况下,最好通知等待某个对象的所有线程。如果这样做,可以在对象上使用notifyAll()让所有在此对象上等待的线程冲出等待区,返回到可运行状态。
下面给个例子:
/
计算线程
@author leizhimin 2008-9-20 11:15:46
/
public class Calculator extends Thread {
int total;
public void run() {
synchronized (this) {
for (int i = 0; i < 101; i++) {
total += i;
}
}
//通知所有在此对象上等待的线程
notifyAll();
}
}
/
获取计算结果并输出
@author leizhimin 2008-9-20 11:15:22
/
public class ReaderResult extends Thread {
Calculator c;
public ReaderResult(Calculator c) {
thisc = c;
}
public void run() {
synchronized (c) {
try {
Systemoutprintln(ThreadcurrentThread() + "等待计算结果。。。");
cwait();
} catch (InterruptedException e) {
eprintStackTrace();
}
Systemoutprintln(ThreadcurrentThread() + "计算结果为:" + ctotal);
}
}
public static void main(String[] args) {
Calculator calculator = new Calculator();
//启动三个线程,分别获取计算结果
new ReaderResult(calculator)start();
new ReaderResult(calculator)start();
new ReaderResult(calculator)start();
//启动计算线程
calculatorstart();
}
}
运行结果:
Thread[Thread-1,5,main]等待计算结果。。。
Thread[Thread-2,5,main]等待计算结果。。。
Thread[Thread-3,5,main]等待计算结果。。。
Exception in thread "Thread-0" javalangIllegalMonitorStateException: current thread not owner
at javalangObjectnotifyAll(Native Method)
at threadtestCalculatorrun(Calculatorjava:18)
Thread[Thread-1,5,main]计算结果为:5050
Thread[Thread-2,5,main]计算结果为:5050
Thread[Thread-3,5,main]计算结果为:5050
Process finished with exit code 0
运行结果表明,程序中有异常,并且多次运行结果可能有多种输出结果。这就是说明,这个多线程的交互程序还存在问题。究竟是出了什么问题,需要深入的分析和思考,下面将做具体分析。
实际上,上面这个代码中,我们期望的是读取结果的线程在计算线程调用notifyAll()之前等待即可。 但是,如果计算线程先执行,并在读取结果线程等待之前调用了notify()方法,那么又会发生什么呢?这种情况是可能发生的。因为无法保证线程的不同部分将按照什么顺序来执行。幸运的是当读取线程运行时,它只能马上进入等待状态----它没有做任何事情来检查等待的事件是否已经发生。 ----因此,如果计算线程已经调用了notifyAll()方法,那么它就不会再次调用notifyAll(),----并且等待的读取线程将永远保持等待。这当然是开发者所不愿意看到的问题。
因此,当等待的事件发生时,需要能够检查notifyAll()通知事件是否已经发生。
通常,解决上面问题的最佳方式是将
×××××××××××××××××××××××××××××
以上来自>
本文分析了Eclipse中多线程程序的实现 讨论了在Eclipse客户端程序开发中应用多线程的方法和要注意的问题 同时也讨论了多线程程序的一些调试和问题解决的方法
Eclipse作为一个开发平台 使用越来越广泛 基于Eclipse Rich Client Platform开发的客户端程序也越来越多 在当今越来越复杂的应用环境中 我们的客户端程序不可避免的要同时进行多任务的处理 一个优异的客户端程序都会允许用户同时启动多个任务 从而大大提高用户的工作效率以及用户体验 本文中我们来谈谈Eclipse中实现多任务的方式
在我们基于Eclipse的Java程序中 我们有很多种方式提供多任务的实现 熟悉Java的朋友立即会想到Java的Thread类 这是Java中使用最多的一个实现多任务的类 Eclipse平台为多任务处理提供了自己的API 那就是Job以及UIJob Eclipse中的Job是对Java Thread的一个封装 为我们实现多任务提供了更方便的接口 以下是Job的基本用法
清单 Job用法示例
Job job = new Job( Job Name ){protected IStatus run(IProgressMonitor monitor) { // 在这里添加你的任务代码 return Status OK_STATUS; }};job schedule(delayTime);在Eclipse中我们也会经常用到Display asynchExec() 和Display synchExec()来启动任务的执行 这两个方法主要为了方便我们完成界面 *** 作的任务 以下是Display asynchExec()的用法 Display synchExec()和它类似
清单 Display synchExec()用法示例
Display getDefault() asyncExec(new Runnable() {public void run() { // 在这里添加你的任务代码 } });通常 在Eclipse中我们最好使用Eclipse提供的Job接口来实现多任务 而不是使用Java的thread 为什么呢?主要有以下几个原因
Job是可重用的工作单元 一个Job我们可以很方便的让它多次执行 Job提供了方便的接口 使得我们在处理中能够很方便的与外界交流 报告当前的执行进度 Eclipse提供了相应的机制使得程序员可以方便的介入Job的调度 例如我们可以方便的实现每次只有一个同一类型的Job在运行 Eclipse缺省提供了Job管理的程序 可以查看当前所有的Job和它们的进度 也提供UI终止 暂停 继续指定的Job 使用Job可以提高程序的性能 节省线程创建和销毁的开销 Eclipse中的Job封装了线程池的实现 当我们启动一个Job时 Eclipse不会马上新建一个Thread 它会在它的线程池中寻找是否有空闲的线程 如果有空闲线程 就会直接用空闲线程运行你的Job 一个Job终止时 它所对应的线程也不会立即终止 它会被返回到线程池中以备重复利用 这样 我们可以节省创建和销毁线程的开销 下面我们从几个方面来讨论Eclipse中Job的实现和使用方面的问题
Eclipse中Job的实现
Eclipse的核心包中提供了一个JobManager类 它实现了IJobManager接口 Eclipse中Job的管理和调度都是由JobManager来实现的 JobManager维护有一个线程池 用来运行Job 当我们调用Job的schedule方法后 这个Job会被JobManager首先放到一个Job运行的等待队列中去 之后 JobManager会通知线程池有新的Job加入了运行等待队列 线程池会找出一个空闲的线程来运行Job 如果没有空闲线程 线程池会创建一个新的线程来运行Job 一旦Job运行完毕 运行Job的线程会返回到线程池中以备下次使用 从上面Job运行的过程我们可以看到 JobManager介入了一个Job运行的全过程 它了解Job什么时候开始 什么时候结束 每一时候Job的运行状态 JobManager将这些Job运行的信息以接口的方式提供给用户 同时它也提供了接口让我们可以介入Job的调度等 从而我们拥有了更加强大的控制Job的能力
为了我们更方便的了解Job所处的状态 JobManager设置Job的一个状态标志位 我们可以通过Job的getState方法获得Job当前的状态值以了解其状态
NONE 当一个Job刚构造的时候 Job就会处于这种状态 当一个Job执行完毕(包括被取消)后 Job的状态也会变回这种状态 WAITING:当我们调用了Job的shedule方法 JobManager会将Job放入等待运行的Job队列 这时Job的状态为WAITING RUNNING:当一个Job开始执行 Job的状态会变为RUNNING SLEEPING:当我们调用Job的sleep方法后 Job会变成这一状态 当我们调用schudule方法的时候带上延时的参数 Job的状态也会转入这一状态 在这一段延时等待的时间中 Job都处于这一状态 这是一种睡眠状态 Job在这种状态中时不能马上转入运行 我们可以调用Job的wakeup方法来将Job唤醒 这样 Job又会转入WAITING状态等待运行
lishixinzhi/Article/program/Java/gj/201311/27703
创建一个线程有两个办法:
1直接继承thread类
2实现runnable接口
在自己的新类中一定要重写run()方法,
启动线程用 类对象名start()
同步就在方法前加上synchronized关键字
创建线程有两种方法:继承Thread类和实现Runnable接口。
方法一:继承 Thread 类,覆盖方法 run(),我们在创建的 Thread 类的子类中重写 run() ,加入线程所要执行的代码即可。下面是一个例子:
public class MyThread extends Thread {
int count= 1, number;
public MyThread(int num) {
number = num;
Systemoutprintln("创建线程 " + number);
}
public void run() {
while(true) {
Systemoutprintln("线程 " + number + ":计数 " + count);
if(++count== 6) return;
}
}
public static void main(String args[]) {
for(int i = 0; i < 5; i++) new MyThread(i+1)start();
}
}
方法二:实现 Runnable 接口
Runnable 接口只有一个方法 run(),我们声明自己的类实现 Runnable 接口并提供这一方法,将我们的线程代码写入其中,就完成了这一部分的任务。但是 Runnable 接口并没有任何对线程的支持,我们还必须创建 Thread 类的实例,这一点通过 Thread 类的构造函数public Thread(Runnable target);来实现。下面是一个例子:
public class MyThread implements Runnable {
int count= 1, number;
public MyThread(int num) {
number = num;
Systemoutprintln("创建线程 " + number);
}
public void run() {
while(true) {
Systemoutprintln("线程 " + number + ":计数 " + count);
if(++count== 6) return;
}
}
public static void main(String args[]) {
for(int i = 0; i < 5; i++) new Thread(new MyThread(i+1))start();
}
}
两种方法各有千秋,可以灵活运用。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)