此程序的结果应与1或2或3个线程相同。但是,线程1的结果是真实的。我想我正在使用共享和私有变量,我做错了什么?线程必须从堆栈读取一个间隔,然后计算正交模型。如果误差足够小(即在指定的精度内),那么我们就有了解决方案。如果误差仍然太大,则将间隔分成两个,每半个间隔给出一半所需的误差。应用正交 再次等等,直到错误足够小。 主要问题是由于提前终止而产生的 线程。堆栈可能为空,但另一个线程可能即将在其上放置新任务。对此的解决方案是保持“活动”线程的计数,即当前正在处理间隔的线程。然后代码应该只在堆栈为空并且没有活动线程时终止...
请,任何帮助都会非常感激吗?
干杯
import java.lang.Integer;
class quadtest {
/* Adaptive Quadrature Code. Finds the value of an integral of a
function on a closed interval to a specified accuracy.
*/
public static void main (String args[]) {
int nthreads = Integer.parseInt(args[0]);
double left, right, eps;
double start_time, time;
Quad quad =null;
//Counter counter = new Counter();
left = 0.0;
right = 1.0;
eps = 1.0E-11;
System.out.println("Adaptive Quadrature Program \n");
System.out.println("eps="+eps+" n=10000");
start_time = System.currentTimeMillis();
//Start threads
Thread thread_object [] = new Thread[nthreads];
for(int i=0;i<nthreads;i++){
quad = new Quad(left,right,eps,i,nthreads);
thread_object[i]=new Thread(quad);
}
for(int i=0;i<nthreads;i++){
thread_object[i].start();
}
//Join the threads
for(int i=0;i<nthreads;i++){
try{
thread_object[i].join();
}catch(InterruptedException x){}
}
time = (double) (System.currentTimeMillis()-start_time) / 1000.;
System.out.println("Result = " + quad.getResult() );
System.out.println("Execution time = " + time + " seconds ");
}
}
import java.lang.Runnable;
import java.util.concurrent.atomic.AtomicInteger;
class Quad implements Runnable{
//Shared Variables
static volatile double [][] stack;
static volatile boolean first=false;
static volatile double FinalResult;
static AtomicInteger threadCounter;
static AtomicInteger writing;
static AtomicInteger stackpointer;
static int nthreads;
//Constants
static final int stacksize = 1000;
static final int il = 0;
static final int ir = 1;
static final int ie = 2;
static final int dims = 3;
//Private Variables
private int tid;
double left,right,eps;
private double result;
private double l,r,ep;
public Quad(double left, double right, double eps,int tid,int nthreads) {
this.left = left;
this.right = right;
this.eps = eps;
this.tid=tid;
Quad.nthreads = nthreads;
result = 0.0;
//Only one thread will do it
if(first==false){
first=true;
stack = new double [dims][stacksize];
threadCounter= new AtomicInteger(0);
writing = new AtomicInteger(0);
stackpointer = new AtomicInteger(1);
stack[il][stackpointer.get()] = left;
stack[ir][stackpointer.get()] = right;
stack[ie][stackpointer.get()] = eps;
FinalResult=0.0;
}
}
public void run(){
stackops();
add();
}
public void stackops() {
double abserror,m, est1, est2;
while ((stackpointer.get() >= 1)|| threadCounter.get()>0) {
// Pop next interval off stack.
synchronized (this){
threadCounter.incrementAndGet();
while (writing.get()==1){}
pop();
}
// Compute estimates.
m = 0.5 * (l + r);
est1 = 0.5 * (r - l) * (func(l) + func(r)) ;
est2 = 0.5 * ((m - l) * (func(l) + func(m)) + (r - m) *
(func(m) + func(r)));
abserror = Math.abs(est2-est1) / 3.0;
// Check for desired accuracy: push both halves onto the
// stack if not accurate enough.
if (abserror <= ep) {
result += est2;
//System.out.println("ERROR->ID "+tid+"-abserror="+abserror+"-ep="+ep );
//System.out.flush();
} else {
if (stackpointer.get()+ 2 > stacksize) {
System.out.println("Stack too small, try stacksize = "
+ 2*stacksize);
}
//Push into the stack
synchronized (this){
push(m);
}
}//end else
threadCounter.decrementAndGet();
}//end while
}//end method
private synchronized void add(){
FinalResult +=result;
}
private void pop(){
if(stackpointer.get()>0){
l = stack[il][stackpointer.get()];
r = stack[ir][stackpointer.get()];
ep = stack[ie][stackpointer.get()];
stackpointer.decrementAndGet();
}
}
private void push (double m){
writing.set(1);
if(stackpointer.get()>=-1){
stackpointer.incrementAndGet();
stack[il][stackpointer.get()] = l;
stack[ir][stackpointer.get()] = m;
stack[ie][stackpointer.get()] = ep * 0.5;
stackpointer.incrementAndGet();
stack[il][stackpointer.get()] = m;
stack[ir][stackpointer.get()] = r;
stack[ie][stackpointer.get()] = ep * 0.5;
}
writing.set(0);
}
public double getResult(){
return FinalResult;
}
private double func(double x) {
double q;
int n;
n = 10000;
q = 1000.0;
for(int i=0;i<n;i++) {
q -= x;
}
if (q == 1.0e10) System.out.println("q = " + q);
return x * x;
}
}
答案 0 :(得分:2)
您的代码实际上没有任何互斥。
synchronized
关键字时,必须实际同步所有线程共享的对象。但是,this
语句中的synchronized(this){}
引用了未共享的Quad
个对象。FinalResult
的写入未同步。此外,volatile
是不必要的。writing
作为自定义旋转循环来防止多个线程同时弹出。你不需要这个 - 你的synchronized
块应该已经处理好这个 - 你弄错了。想象一下,一个线程开始执行pop()
,在它可以进行第一次写操作之前,它会被重新安排。另外,你也有push
的写作,没有保护。如果pop()
和push()
被两个独立的线程同时调用怎么办?其他说明:
stackPointer
不需要原子。您也可以初始化为static
数据定义对象的数据。即:
class Quad implements Runnable {
static AtomicInteger threadCounter = new AtomicInteger(0);
...
}
答案 1 :(得分:0)
如果没有阅读所有代码但只看了它,似乎这就是JDK 7中首次亮相的join / fork框架旨在解决的问题。见http://blog.quibb.org/2010/03/jsr-166-the-java-forkjoin-framework/
我建议不要乱用线程和同步。 JDK 7版本已经可以下载(并且看起来相当稳定)。另外,还有一个独立的连接/表单版本可以单独下载(参见http://g.oswego.edu/dl/concurrency-interest/)。
答案 2 :(得分:0)
类Quad实现Runnable { //共享变量 static volatile double [] [] stack; static volatile boolean first = true; static Object lock1; static Object lock2; static double FinalResult; static AtomicInteger threadCounter; static AtomicInteger stackpointer; static int nthreads; //常量 static final int stacksize = 1000; static final int il = 0; static final int ir = 1; static final int ie = 2; static final int dims = 3; //私有变量 int tid; 双左,右,eps;
private double result;
private double l,r,ep;
private boolean calculate;
public Quad(double left, double right, double eps,int tid,int nthreads) {
this.left = left;
this.right = right;
this.eps = eps;
this.tid = tid;
Quad.nthreads = nthreads;
result = 0.0;
synchronized(this){
//Only the first thread will do it
if(first==true){
first=false;
lock1 = new Object();
lock2 = new Object();
stack = new double [dims][stacksize];
threadCounter= new AtomicInteger(0);
stackpointer = new AtomicInteger(1);
stack[il][stackpointer.get()] = left;
stack[ir][stackpointer.get()] = right;
stack[ie][stackpointer.get()] = eps;
FinalResult=0.0;
System.out.println("I am tid= "+tid );
}
}
}
public void run(){
stackops();
add();
}
public void stackops() {
double abserror,m, est1, est2;
est2=est1=m=abserror=0;
while ((stackpointer.get() >= 1)|| threadCounter.get()>0) {
// Pop next interval off stack.
synchronized (lock1){
pop();
}
// Compute estimates.
if (calculate == true){
m = 0.5 * (l + r);
est1 = 0.5 * (r - l) * (func(l) + func(r)) ;
est2 = 0.5 * ((m - l) * (func(l) + func(m)) + (r - m) *
(func(m) + func(r)));
abserror = Math.abs(est2-est1) / 3.0;
if (abserror <= ep) {
result += est2;
} else {
//Push into the stack
synchronized (lock1){
push(m);
}
}//end else
threadCounter.decrementAndGet();
}
}//end while
System.out.println("I am " + tid+" result = "+result);
}//end method
private void add(){
synchronized(lock1){
FinalResult +=result;
}
}
private void pop(){
if(stackpointer.get()>0){
threadCounter.incrementAndGet();
calculate =true;
l = stack[il][stackpointer.get()];
r = stack[ir][stackpointer.get()];
ep = stack[ie][stackpointer.get()];
stackpointer.decrementAndGet();
}else{
calculate =false;
}
}
private void push (double m){
if(stackpointer.get()>=-1){
stackpointer.incrementAndGet();
stack[il][stackpointer.get()] = l;
stack[ir][stackpointer.get()] = m;
stack[ie][stackpointer.get()] = ep * 0.5;
stackpointer.incrementAndGet();
stack[il][stackpointer.get()] = m;
stack[ir][stackpointer.get()] = r;
stack[ie][stackpointer.get()] = ep * 0.5;
}
}
public double getResult(){
return FinalResult;
}
private double func(double x) {
double q;
int n;
n = 10000;
q = 1000.0;
for(int i=0;i<n;i++) {
q -= x;
}
if (q == 1.0e10) System.out.println("q = " + q);
return x * x;
}
}