我有一个数组:int [] arr = {5,4,3,1,2};
I want to do like this::
5 should be read by thread one
4 should be read by thread two
3 should be read by thread one
1 should be read by thread two
2 should be read by thread one
我已经尽力了这个简单的程序:
package com.techighost.create.deadlock;
public class ArrayReading implements Runnable {
volatile int index = 0;
int[] arr;
public ArrayReading(int[] arr) {
this.arr = arr;
}
@Override
public void run() {
synchronized (arr) {
for (;index<=(arr.length-1);) {
if (index % 2 == 0 && Thread.currentThread().getName().equals("Thread-One")) {
System.out.println(arr[index] + " " + Thread.currentThread().getName());
index++;
arr.notify();
} else if (index % 2 != 0 && Thread.currentThread().getName().equals("Thread-Two")) {
System.out.println(arr[index] + " " + Thread.currentThread().getName());
index++;
arr.notify();
}else{
System.out.println("In else " + Thread.currentThread().getName());
try {
arr.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) throws InterruptedException {
int[] arr = { 5, 4, 3, 1, 2 };
ArrayReading arrayReading = new ArrayReading(arr);
Thread t = new Thread(arrayReading);
t.setName("Thread-One");
Thread t1 = new Thread(arrayReading);
t1.setName("Thread-Two");
t.start();
t1.start();
t.join();
t1.join();
}
}
我认为这个线程名称检查不应该存在?任何正文请建议如何删除此项检查
答案 0 :(得分:3)
你可以使用@ zzk.Program提到的条件 对于这可以是
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class PrintSequentially {
private final int[] items;
private final ReentrantLock lock;
private final Condition notEven;
private final Condition notOdd;
private int currentCount = 0;
public PrintSequentially(int[] items) {
this.items = items;
this.lock = new ReentrantLock();
this.notEven = lock.newCondition();
this.notOdd = lock.newCondition();
}
public void printSeq() throws InterruptedException {
try {
lock.lockInterruptibly();
while (currentCount < items.length) {
if (currentCount % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ":"
+ items[currentCount++]);
if (currentCount < items.length)
notEven.await();
notOdd.signal();
} else {
System.out.println(Thread.currentThread().getName() + ":"
+ items[currentCount++]);
notEven.signal();
if (currentCount < items.length)
notOdd.await();
}
}
} finally {
lock.unlock();
}
}
}
此驱动程序是
public static void main(String[] args) {
int arr[] ={1,2,3,4,5};
final PrintSequentially p = new PrintSequentially(arr);
Runnable r1 = new Runnable() {
@Override
public void run() {
try {
p.printSeq();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Runnable r2 = new Runnable() {
@Override
public void run() {
try {
p.printSeq();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread th1 = new Thread(r1);
th1.setName("thread 1");
th1.start();
Thread th2 = new Thread(r2);
th2.setName("thread 2");
th2.start();
}
在这里,您可以添加任意数量的线程。它将按顺序打印。
答案 1 :(得分:2)
你可以使用条件。线程1应该等待条件索引%2 == 0并且线程2应该等待条件索引%2 == 1.
的此链接答案 2 :(得分:1)
在runnable中使用另一个参数字段来告诉它读取偶数或奇数索引,创建两个runnable实例,一个用于even,一个用于odd。设置一个至少包含两个线程的ExecutorService
,执行runnables。可能有可能它们完成得太快而无法给出不同的线程。没试过这个。
答案 3 :(得分:1)
您可以使用wait
和notify
这样的线程间通信:
class ReadNum
{
int arr[];
private volatile int counter = 0;
public ReadNum()
{
counter = 0 ;
}
public ReadNum(int size)
{
arr = new int[size];
for (int i = 0; i < size ; i++)
{
arr[i] = i;
}
}
public void setArray(int[] arr)
{
counter = 0;
this.arr = arr;
}
public synchronized void readOdd()
{
while (counter < arr.length)
{
if (counter % 2 != 0)
{
System.out.println(Thread.currentThread().getName()+":->"+arr[counter]);
counter++;
}
notify();
try{
wait();
}catch(Exception ex){ex.printStackTrace();}
}
notify();//So that other EvenThread does'nt hang if OddThread completes earlier
}
public synchronized void readEven()
{
while (counter < arr.length)
{
if (counter % 2 == 0)
{
System.out.println(Thread.currentThread().getName()+":->"+arr[counter]);
counter++;
}
notify();
try{
wait();
}catch(Exception ex){ex.printStackTrace();}
}
notify();//So that other OddThread does'nt hang if EvenThread completes earlier
}
}
public class SequenceRead
{
public static void main(String st[])
{
final ReadNum rn = new ReadNum();
int arr[]= {1,2,34,78,99,45,4545,987,343,45};
rn.setArray(arr);
Thread th1 = new Thread(new Runnable()
{
@Override
public void run()
{
rn.readEven();
}
},"EvenReadThread");
Thread th2 = new Thread( new Runnable()
{
@Override
public void run()
{
rn.readOdd();
}
},"OddReadThread");
th2.start();th1.start();
}
}
<强>更新强>
以下是您要求了解种族条件的解释。
竞争条件:“这是多线程可以访问相同资源(通常是对象的实例变量)的情况,并且可以 如果一个线程“竞争”或“偷偷溜进”,则会产生损坏的数据 在应该是原子的操作完成之前很快。因此,程序的输出是不可预测的,因为它取决于访问相同资源的各种线程的启动,执行和完成的顺序或时间。“
例如,考虑下面给出的代码:
class Race
{
private int counter;
public void printCounter()
{
while(counter < 100)
{
try
{
Thread.sleep(10);//Added to show Race Effect.
}
catch (Exception ex){}
counter = counter + 1;
}
System.out.println(Thread.currentThread().getName() +" : "+counter);//If we don't consider Race condition then the Output should be 100 for all threads.
}
}
public class MainClasss
{
public static void main(String st[])
{
final Race race = new Race();
Thread[] th = new Thread[2];
//Creating 2 threads to call printCounter of object race
for (int i = 0 ; i < th.length ; i++)
{
th[i] = new Thread( new Runnable()
{
public void run()
{
race.printCounter();
}
}, "Thread"+i);
}
//Starting all Threads
for (Thread thr : th )
{
thr.start();
}
}
}
这是我得到的输出,它可能会因你的系统而异。
Thread1 : 100
Thread0 : 101
所有线程都没有按预期打印100! 为什么?因为程序无法控制执行线程何时被另一个线程抢占。这完全取决于JVM线程调度程序。
上述输出的可能解释之一如下:
- 在counter = 99时,Thread1潜入while循环并睡眠10 ms。
- JVM Scheduler现在已经通过Thread0抢占了Thread1。
- Thread1进入“while”循环,因为它找到了计数器&lt; 100
- 在Thread.sleep中,Thread0被Thread1抢占。
- Thread1将计数器增加1。
- Thread1将计数器值打印为100并完成。
- Thread0继续执行并将计数器增加1并使计数器= 101
- Thread0将计数器值打印为101并完成。
醇>
这是Race Condition的现场展览
要避免此Race条件,您应该将ReadNum
方法设置为synchronized,这样当Thread进入该方法时,它会占用监视器并成为synchronized方法的所有者。并且该线程仅在完成所有操作原子后才被抢占。我希望它现在能让你对种族条件有一个很好的了解。
答案 4 :(得分:1)
我知道这可能是某种让你的脚湿润的线程应用程序,但是它有很多问题使它不是最佳的。
使用线程的重点是异步操作。希望你的线程处理数组中的每个其他条目听起来像你正在划分工作,但这可能比单线程运行慢,因为同步完成了彼此。线程的性质也意味着&#34; 2&#34;可以在&#34; 1&#34;之前打印。这是一件好事,因为你没有放慢线程以使它们井然有序。
您的代码在这里有一些竞争条件。例如,一个线程可以处理列表的最后一个元素并转到wait
,但另一个线程可能已经完成了列表并且不会在那里notify
。我打赌你的申请通常会在最后挂起。
您应该考虑使用executor service并为每个条目提交作业。这是执行大多数线程任务的最佳方法:
// create a thread pool with 2 workers
ExecutorService threadPool = Executors.newFixedThreadPool(2);
for (int entry : arr) {
threadPool.submit(new `(entry));
}
// once we have submitted all jobs to the thread pool, it should be shutdown
threadPool.shutdown();
// to wait for the jobs to finish you do
threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
...
然后您的ArrayReading
将条目不整个数组,并且可以独立处理它们。
最后,正如其他人已经提到的那样,您可以传递boolean even
标志,让每个线程处理偶数(如果为真)或奇数(如果为假)项。
Thread t1 = new Thread(new ArrayReading(arr, true));
Thread t2 = new Thread(new ArrayReading(arr, false));
答案 5 :(得分:0)
这是您要寻找的代码....
public class ThreadConcurrent {
int []array=new int[]{0,1,2,3,4,5,6,7,8,9};
volatile int i=0;
public void checkSum() {
synchronized (this) {
for(;i<array.length;){
System.out.println("thread name "+Thread.currentThread().getName()+ " : "+array[i]);
i++;
notify();
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
final ThreadConcurrent er=new ThreadConcurrent();
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
er.checkSum();
}
}, "T1");
Thread t21=new Thread(new Runnable() {
@Override
public void run() {
er.checkSum();
}
}, "T2");
t1.start();
t21.start();
}
}