在学习线程之前我们先来回顾下进程,进程就是正在运行的程序的实例,是系统分配资源的基本单位。那么线程与进程有什么关系呢?通常情况,线程是进程的一个实体,是进程的一种表现。那么我们几下来就一起学习下线程:
首先我们通过一个实例来说明,这个实例的需求是:通过产生一个随机数组,然后对其排序并且输出数组,这样交替输出三次。可能有很多种方式实现,但是我们为了说明问题,这里我们用线程控制的方式来实现,下面我们首先分析下题干:
1.需要一个随机数的生成器。
2.我们需要把生成的一个随机数组作为一个输入。(这里的输入输出共享一个数组)
3.我们需要对输入进行排序。
4.我们需要输出数组。
5.输入输出交替进行三次。(每次初始化输入后,然后就输出其内容)
下面我们开始编码:
产生随机数的方法
public int[] initArray()
{
int array[] = new int[5];
int i;
Random rd= new Random();
for(i=0;i<array.length;i++)
{
array[i]=rd.nextInt(99)+1;
}
return array;
}
定义一个输入输出共享操作的一个数组:
public class InitList {
int arry[];
boolean flag=false;//用来标示当前的线程的操作
public int[] getArry() {
return arry;
}
public void setArry(int[] arry) {
this.arry = arry;
}
}
接下来我们就初始化输入,由于要用到线程来控制输入输出之间的切换,所以我们要使用一个同步的机制来控制输入输出对共享区域的内容有序的操作(一输入,一输出)。
public class InitInput implements Runnable{
InitList IL;
public InitInput(InitList IL)
{
this.IL=IL;
}
@Override
public void run() {
// TODO Auto-generated method stub
int x=0;
int array[];
RandomMethod rm =new RandomMethod();
while(x<3)
{
synchronized(IL)
{
if(IL.flag){
try{
IL.wait();
}catch(Exception e){
//
}
}
if(x<3){
array=rm.initArray();
IL.setArry(rm.sort(array));
}
IL.flag=true;
IL.notify();
x++;
}
}
}
}
细心的应该会发现我们这里有一个对初始化输入的数组进行了排序,这里的排序我使用的是蛮力算法中的选择排序:
public int[] SelectSort(int array[]){
int i,j;
int min;
for(i=0;i<array.length-1;i++)
{
min=i;
for(j=i+1;j<array.length;j++)
{
if(array[j]<array[min])
{
min=j;
}
}
swap(array,min,i);
}
return array;
}
static void swap(int array[],int i,int j)
{
int temp;
temp=array[i];
array[i]=array[j];
array[j]=temp;
}
上面我们初始化了输入,那么接下来我们就要开始实现输出部分的操作:
public class InitOutput implements Runnable{
InitList IL;
public InitOutput(InitList IL)
{
this.IL=IL;
}
@Override
public void run() {
// TODO Auto-generated method stub
int arry[];
int x=0;
while(x<3){
synchronized(IL){
if(!IL.flag){
try{
IL.wait();
}catch(Exception e){
//
}
}
arry=IL.getArry();
System.out.print(Thread.currentThread().getName()+":");
for(int i=0;i<arry.length;i++){
System.out.print("V---:"+arry[i]);
}
System.out.println();
IL.flag=false;
IL.notify();
x++;
}
}
}
}
好,万事具备,只差main方法了:
public class Main {
public static void main(String args[]){
InitList IL=new InitList();
InitInput II=new InitInput(IL);
InitOutput IO = new InitOutput(IL);
Thread t1 = new Thread(II);
Thread t2 = new Thread(IO);
t1.start();
t2.start();
}
}
这样我们就实现可开始提出的需求。
现在我们再仔细的分析一些细节:
首先随机数这一块内容比较简单,我们只需要实例化一个Random,然后使用的他的nextInt方法来产生随机数:
Random rd=new Random();
rd.nextInt(99)+1;//这样我们就可以产生一个1-100 之前的一个数。
下面关键在线程操作这里:
首先使用线程有两种方式(1.实现Runnable接口;2.继承线程),我们比较常用的就是实现Runnable的方式。因为我们可以避免单继承的局限性,然后可以与父类Thread分离出来,单独封装在一个对象里做操作。那么线程的运行机制是什么呢?下面我们通过一张图可能会比较容易理解:
在这个基础之上呢,我们在main方法中创建了两个线程的实例,然后通过start去启动,然后我们在输入与输出这两部分里面,都使用了wait()和notify()这两个方法,我们判断flag的值,如果list中有值,那么我们就输出,通过wait释放当前线程的执行权,然后通过notify()来唤醒另一个线程执行。这样一直到他的生命的结束。这里我们同时使用了一个关键字synchronized,这是实现同步的问题,这里我们涉及到连个线程共享同一数据,所以涉及到线程的安全问题,所以我们必须实现同步锁来控制对共享数据的操作。作为线程安全问题,其实售票是一个非常好的案例。这里我就不啰嗦了,如果还有不太清楚的,我可以展示一个实例给大家,其实也是非常简单的。说到这里就差不多了,线程这部分内容是我的一块心病,一直不敢碰触,因为受到前辈们的影响,感觉非常的难以理解。但是最后还是决心去研究一番,不过收获不小,感觉学习线程也是非常有意思的。