Java多线程的基础知识总结(1)

Java多线程的基础知识总结——进程的建立

不得不说软件构造的实验虽然很难,但是都很有针对性,确实让我学到了不少。借着做实验的集合我来总结一下多线程的基础知识
要对多线程中各个线程的状态进行一个总结,就不得不看这张图
在这里插入图片描述
这张图包含了Thread的各种状态和进入状态使用的函数。

Java线程的一些重要状态

从上图可以看到线程一共有5种状态,但是我觉得需要理解的状态有3种
就绪状态(Runnable):当调用线程对象的start()方法,线程即进入就绪状态。这个状态只表示它可以开始了,并不表示它马上就会开始,在多个线程都进入就绪状态的情况下,cpu先执行哪个完全是随机的

运行状态(Running):一旦cpu选择某个就绪状态的线程并开始执行,这个线程就进入了执行状态,它就会沿着run()方法中的代码一行一行执行

阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。而在此期间其他的线程不受影响继续执行。根据阻塞产生的原因不同,阻塞状态又可以分为三种:

1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态,直到被其他线程唤醒才会进入就绪状态(注意保证wait和notify的执行顺序,否则有可能发生永远不会被唤醒的情况);
2.同步阻塞 – 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态,直到锁被释放时才会进入就绪状态(并不是锁释放就会立刻开始运行,还是会和同样运行到这里其他线程争夺资源的使用权);
3.其他阻塞 – 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态结束、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

怎么创建一个进程

这一块网上内容很多有很详细,我就不仔细讲了,简略说说:
在Java中进程是一个类——Thread类。
第一种方法:我们可以直接继承Thread类,重写里面的run函数

public class Threadtest extends Thread{
  @Override
  public void run() {
    //在这里重写你的方法
  }
}

第二种方法:我们注意到Thread类的声明中,run()方法是如下声明的

/* What will be run. */
private Runnable target;

public void run() {
        if (target != null) {
            target.run();
        }
    }

说明第一种方法其实不是Thread希望我们使用的方法。target是一个继承了runnable接口的类的实例。如此,我们就可以声明一个类继承runnable接口,并实现run()方法,在Thread实例化时作为参数传入,这样Thread就可以执行我们写的类的run()方法了

public class Threadtest  {
  void test() {
    Thread a=new Thread(new runit());
  }
  class runit implements Runnable {
    public void run() {
      //在这里写你的方法
    }
  }
}

第三种方法:虽然实现run()方法就可以实现一个进程对象,但run()方法并没有返回值,这对某些情况并不友好。使用封装的思想,Java为我们提供了一个新的接口callable<>,首先来看看它的使用方式

public class Threadtest  {
  void test() {
    FutureTask<Integer> b=new FutureTask<Integer>(new runit())
    Thread a=new Thread();
    b.get(); //得到返回值
    
  }
  class runit implements Callable<Integer> {
    public Integer call() {
      //在这里写你的方法
      return null;
    }
  }
}

可以看到实现callable接口的类要被FutureTask类封装之后才能传入Thread被执行。让我们仔细看看FutureTask是如何实现run()方法的

public void run() {
        if (state != NEW ||
            !RUNNER.compareAndSet(this, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

FutureTask向下调用了callable的call方法,得到了返回值,向上继承runnable方法。除此之外,它还提供了多种方法来实现检查进程的运行情况等等功能。所以我更推荐使用这种方式创建进程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值