JAVA线程基础概念及使用

时间:2022-06-30 05:27:10

一、线程和进程的区别

  在操作系统中所有运行的任务通常对应一个进程,进程是系统进行资源分配和调度的一个独立单位。线程是进程的组成部分,一个进程最少包含一个线程。并发和并行的区别是,并发指的在同一时刻内,多个指令在多个处理器上同时执行。并发指的是同一个时刻内一个只有一条指令执行,但多个进程指令被快速轮换执行。使得宏观上感觉是多个进程在同时执行。多个线程共享进程的内存资源和数据资源等。而多个进程之间不能共享内存。

  JAVA实现多线程有三种方式:1、继承thread类  2、实现runnable  3、使用Callable和future创建多线程

二、线程的使用方式

第一种方式 继承Thread

package cn.test.hf;

/**
* 继承thread实现多线程
*/
public class CreateThread extends Thread { private int i; public void run() { for (i = 0; i < 100; i++) { // 打印出当前这个线程的名称
System.out.println(this.getName() + "----" + i + "-------" + System.currentTimeMillis());
} } public static void main(String[] args) { for (; i < 100; i++) { System.out.println(Thread.currentThread().getName() + "----" + i + "-------" + System.currentTimeMillis());
if (i == 20) { // 创建两个线程
CreateThread thread1 = new CreateThread();
thread1.start();
CreateThread thread2 = new CreateThread();
thread2.start();
}
} }
}

JAVA线程基础概念及使用

从结果可以看出,当主线程跑到i=20的时候,开始去执行子线程,同时主线程还是在运行着(是否分配了不同的CPU,那么就是并发的运行,如果是单个的话那么就是时间片轮转)。使用继承thread类的方式去实现多线程,实例变量不能共享。类变量可以共享。

第二种方式:实现Runnable

  

package cn.test.hf;

public class RunnableTest implements Runnable {

    public void run() {

        System.out.print("线程名称:" + Thread.currentThread().getName());
} public static void main(String[] args) { RunnableTest r = new RunnableTest();
new Thread(r,"线程1").start();
new Thread(r,"线程2").start();
}
}
这种方式由于使用的是同一个对象,所以实例遍历可以共用。 第三种方式:实现Callable接口,这种实现多线程的方式和runnable类似,只不过Callable方式会带有返回值。
package cn.test.hf;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask; public class CallableTest implements Callable { public Object call() throws Exception { return 1;
} public static void main(String[] args) { try {
CallableTest call = new CallableTest();
FutureTask future = new FutureTask(call); new Thread(future).start();
System.out.print(future.get());
} catch (Exception e) { }
}
} 三种实现多线程的方式对比:实现Runnable和实现Callable方式的优点有1、还可以实现其他的类,可扩展。2、多个线程可以共享同一个target对象,可以共享数据。在代码结构层次可以将CPU、数据、代码分开,形成清晰的模型。
  继承Thread类实现多线程用点是编程方便。三种方式推荐使用Runnable和Callable+Future。 三、线程的生命周期
  1、新建(New)
    程序使用New创建一个线程对象后,该线程的状态处于新增状态,仅仅由JAVA虚拟机为其分配内存,初始化其成员变量的值。
  2、就绪(Runnable)
    调用线程的start方法会将线程改变为就绪状态,还差获得CPU
  3、执行(Running)
    线程就绪状态获得CPU进入执行状态。
  4、阻塞(Blocked)
    线程调用sleep方法主动放弃CPU、线程调用了阻塞式IO方法、线程试图获取一个同步监视器,但是被其他线程所持有、线程在等待某个通知、程序调用了线程的suspend方法将其挂起的时候线程会进入阻塞。阻塞的线程获得某些资源后会进入就绪状态,等待获得调度获得CPU,不会直接进入执行状态。
  5、死亡(Dead)
    线程执行完后就会消亡。使用isAlive方法可以检测线程是否死亡,新建和死亡的线程会返回false、其他的返回true。 四、控制线程
  1、join线程,Thread提供了让线程等待另一个线程的方法join()
  
package cn.test.hf;

public class RunnableTest implements Runnable {

    public void run() {

        for (int i = 0; i < 100; i++) {

            System.out.println("线程名称:" + Thread.currentThread().getName() + "=====" + i);
}
} public static void main(String[] args) { try { RunnableTest r = new RunnableTest();
Thread t1 = new Thread(r, "线程1");
t1.start();
t1.join();
Thread t2 = new Thread(r, "线程2");
t2.start();
for (int i = 0; i < 1000; i++) { System.out.println("线程名称:" + Thread.currentThread().getName() + "=====" + i);
}
} catch (Exception e) { }
}
} 2、后台线程又称为守护线程,JVM垃圾回收就是典型的一个守护线程,守护线程会在所有前台线程死亡后再死亡。使用DaemonThread可以将线程设置为后台线程。
3、线程休眠,调用sleep方法,会将线程变为阻塞状态。
4、线程让步,调用yield方法,会使线程让出CPU进入就绪状态,而不是阻塞当前线程。调用之后其他比当前线程优先级高的线程将会获得CPU。
五、线程的优先级
  子线程的优先级默认与其父线程优先级一致,main主线程的优先级为普通优先级,通过Thread的setPriority方法可以设置线程的优先级,范围为1-10.