java线程基础

来源:互联网 发布:python灰帽子讲的什么 编辑:程序博客网 时间:2024/05/16 05:15

 一、什么是线程
 线程在某些场合可以当做轻量级进程来理解,是程序执行的最小单位(是系统调度和分派的基本单位),线程本身是由唯一id、当前指令针、寄存器集合、堆栈组成。线程是进程中的一个实体,线程本身除运行资源外,不拥有其他系统资源,但是可以与同一个进程组的其他线程共享资源,线程之间是相互制约的,呈现出间断性。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。
二、线程的状态
线程分为5个状态
1、新建:例如:new Thread();这个时候只是新创建了一个线程,线程本身还没有任何代码。
2、就绪:创建线程后 执行了start()方法,会进行线程运行时需要的资源创建,资源创建完成后调用run()方法(这里只是调用 了 run,并没有真正开始执行),当start()正确返回后,线程进入就绪状态。
注:调用了start()方法并不意味着线程会马上执行,可能会由于cup时间片的竞争,或者当前线程需要其他线程占用的资源释放后才能运行,这些情况的出现会延迟当前线程的开始执行时间
3、运行:cup时间片和运行资源被当前线程抢到后 开始执行run()方法,只有开始执行run方法了线程才是运行状态
4、阻塞:简单的来说就是线程由于某种原因暂时停止了继续运行。阻塞只是让出了cpu的时间片,并不是结束掉线程。
    一般有以下情况会导致阻塞:(1)、调用了sleep()方法进行了睡眠。(2)在某个I/O操作上等待,比如网络Socket中服务器监听,或者键盘等待输入,或者等待资源释放等等情况。(3)线程想要得到一个锁,但是资源被其他线程占用,必须等待被占用线程释放资源。(4)线程等待条件触发执行
5、死亡:线程运行完成后自然进入死亡状态,表示线程终结了,如果run()方法中有未捕获的异常产生,会导致线程意外停止。死亡的线程是不能调用start()方法的,会抛出java.lang.IllegalThreadStateException异常
三、如何创建一个线程
1、继承Thread类,实现 public void run(){}方法,这种方法的坏处是一旦A类继承了Thread类,就不可以再被其他类继承A的线程特性,线程方法必须是在A类中直接实现
2、实现Runnable接口,需要实现run()方法,这种方式可以再去继承其他对象。
3、实现Callable接口
  步骤:
(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
(3)使用FutureTask对象作为Thread对象的target创建并启动新线程
代码 ====================
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class Ts implements Callable{

@Override
public Object call() throws Exception {
// TODO Auto-generated method stub
return null;
}
public static void main(String[] args) {
Ts t=new Ts();//由Callable创建一个FutureTask对象
// FutureTask是一个包装器,它通过接受Callable来创建,它同时实现了 Future和Runnable接口
FutureTask task = new FutureTask(t); 
Thread thread = new Thread(task);
thread.start();
}
四、如何结束一个线程
一般线程如果没有重复执行的可能性,那么走完run方法会自然结束掉,也有些其他场景是无限循环的,有3种方式结束线程:
1、使用退出标志控制,在线程外部声明一个布尔对象,线程内部用布尔值来控制线程
代码====================
public volatile boolean exit = false; //使用volatile 修饰,保证当前对象同时只能有一个对象在修改

    public void run() 
    { 
        while (!exit); 
    } 
    public static void main(String[] args) throws Exception 
    { 
        ThreadFlag thread = new ThreadFlag(); 
        thread.start(); 
        sleep(5000); // 主线程延迟5秒 
        thread.exit = true;  // 终止线程thread 
        thread.join(); 
        System.out.println("线程退出!"); 
    } 
2、使用stop方法,这种相当于立即强制性结束掉一个线程
,会导致处理信息丢失等待问题,不到万不得已,还是不要用这种方式。
3、使用interrupt方法
 (1)、在线程处于阻塞状态时使用
interrupt(),如果阻塞原因是调用了 sleep(),那么会抛出异常InterruptedException
 代码======================
public class ThreadInterrupt extends Thread 

    public void run() 
    { 
        try 
        { 
            sleep(50000);  // 延迟50秒 
        } 
        catch (InterruptedException e) 
        { 
            System.out.println(e.getMessage()); 
        } 
    } 
    public static void main(String[] args) throws Exception 
    { 
        Thread thread = new ThreadInterrupt(); 
        thread.start(); 
        System.out.println("在50秒之内按任意键中断线程!"); 
        System.in.read(); 
        thread.interrupt(); 
        thread.join(); 
        System.out.println("线程已经退出!"); 
    } 

 (2)、使用while(!isInterrupted()){}来判断线程是否被中断,如果返回false,就调用interrupt()方法,这样的结果是,线程会找个机会自己退出来
代码================================
public class ThreadA extends Thread {
    private boolean isInterrupted=false;
   int count=0;
   public void interrupt(){
       isInterrupted = true;
       super.interrupt();
      }
   
   public void run(){
       System.out.println(getName()+"将要运行...");
       while(!isInterrupted){
           System.out.println(getName()+"运行中"+count++);
           try{
               Thread.sleep(400);
           }catch(InterruptedException e){
               System.out.println(getName()+"从阻塞中退出...");
               System.out.println("this.isInterrupted()="+this.isInterrupted());
           }
       }
       System.out.println(getName()+"已经终止!");
   }
======关于线程中断
interupt()中断线程
一个线程从运行到真正的结束,应该有三个阶段:正常运行.、处理结束前的工作,也就是准备结束.、结束退出.。

如何能确保线程真正停止?在线程同步的时候有一个叫“二次惰性检测”(double check),能在提高效率的基础上又确保线程真正中同步控制中。那么我把线程正确退出的方法称为“双重安全退出”,就是不以isInterrupted ()为循环条件 

五、线程常用的方法
1、 sleep()这是一个静态方法,只能控制当前正在运行的线程,sleep能保证线程最短不会运行时间,但是不能有效保证多少时间后能继续运行,这与当前cup时间片与系统资源调度有关。
2、getState()得到该线程的状态
3、isAlive()确定当前线程是否处在活动状态。可运行或阻塞返回true,其他状态返回false
4、isInterrupted()判断线程是否被中断,已经中断返回true,否则为false
5、interrupt()中断线程。一个线程强制停止是很危险的,这个方法并不会强制停止线程,而是告诉这个线程自己可以找个地方停下来了。如果无法中断(例如进入一个同步锁代码块时,是不能被中断的),会抛出SecurityException,但是 ReentrantLock 支持可中断的获取模式即 tryLock(long time, TimeUnit unit)。
6、getPriority()返回线程的优先级
7、setPriority()更改线程的优先级
8、join()等待线程终止,有参数可以设置等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。
9、yield ()暂停当前正在执行的线程,并执行其他线程
六、wait()与sleep()的区别
sleep()可以将一个线程睡眠,参数可以指定一个时间。
wait()可以将一个线程挂起,直到超时或者该线程被唤醒。(java.lang.Object类中提供了wait(), notify()和notifyAll()方法来操作线程
1、功能差不多,都用来进行线程控制,他们最大本质的区别是:sleep()不释放同步锁,wait()释放同步锁
2、用法的上的不同是:sleep(milliseconds)可以用时间指定来使他自动醒过来,如果时间不到你只能调用interreput()来强行打断;
                             wait()可以用notify()直接唤起.
 

sleep是Thread类的静态方法。sleep的作用是让线程休眠制定的时间,在时间到达时恢复,也就是说sleep将在接到时间到达事件事恢复线程执行,例如:
try{
System.out.println("I'm going to bed");
Thread.sleep(1000);
System.out.println("I wake up");
}
catch(IntrruptedException e) {
} 
wait是Object的方法,也就是说可以对任意一个对象调用wait方法,调用wait方法将会将调用者的线程挂起,直到其他线程调用同一个对象的notify方法才会重新激活调用者,例如:
try{
obj.wait();
}
catch(InterrputedException e) {
} 
3、
这两者的施加者是有本质区别的
 
 sleep()是让某个线程暂停运行一段时间,其控制范围是由当前线程决定,也就是说,在线程里面决定。
  wait()是由某个确定的对象来调用的,将这个对象理解成一个传话的人,当这个人在某个线程里面说"暂停!",也是obj.wait(),这里的暂停是阻塞 ,再等一个传话人说“ok继续执行”,就继续起来执行
两者都可以让线程暂停一段时间,但是本质的区别是一个线程的运行状态控制,一个是线程之间的通讯的问题 
总结sleep和wait的区别有:
  1,这两个方法来自不同的类分别是Thread和Object
  2,最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
  3,wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在
    任何地方使用
   synchronized(x){
      x.notify()
     //或者wait()
   }
   4,sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常 


0 0