Java多线程(1)
1.线程的六种状态
- 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。(尚未启动的线程)
- 运行(RUNNABLE):可运行线程的线程状态。状态为runnable的线程正在Java虚拟机中执行,但是它可能正在等待来自操作系统的其他资源,例如处理器。
- 阻塞(BLOCKED):表示线程阻塞于锁。
- 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
- 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
- 终止(TERMINATED):线程的终止状态,表示该线程已经执行完毕。
以下是Thread类中定义的几种状态:
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
线程等待线程状态。 线程处于等待状态,因为调用下列方法之一:
1. Object.wait不带超时
2. Thread.join没有超时
3. LockSupport.park
在等待状态的线程正在等待另一个线程来执行特定动作。 例如,一个已调用的Object.wait()的对象上正在等待另一个线程在该对象上调用Object.notify()或Object.notifyAll()。 已调用的Thread.join()正在等待指定线程终止。
哪些方法使线程处于超时等待状态由于使用指定的正等待时间调用以下方法之一,线程处于定时等待状态:
1. Thread.sleep
2. Object.wait 带超时
3. Thread.join 带超时
4. LockSupport.parkNanos
5. LockSupport.parkUntil
2. 线程的创建方式
2.1 继承Thread类,重写run()方法
public class MyThread extends Thread {
private String name;
public MyThread(String name) {
this.name = name;
}
@Override
public void run() {
for (int i = 0; i <5 ; i++) {
System.out.println("name:"+name+">>>>>>"+Thread.currentThread().getName());
}
}
}
class Test{
public static void main(String[] args) {
//直接创建Thread的子类对象创建线程。
MyThread t1=new MyThread("t1");
MyThread t2=new MyThread("t2");
//调用start方法启动线程并调用run()方法
t1.start();
t2.start();
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName());
}
}
}
run()和start()的区别:
- run():仅仅是封装了被线程执行的代码,直接调用就是普通方法
- start():首先是启动了线程,然后再由jvm去调用了该线程的run()
获取线程名称:Thread.currentThread().getName()
设置线程名称:setName()、Thread(Runnable target, String name)
2.2 实现Runnable接口
public class MyThread2 implements Runnable {
//多线程的实现方案二:实现Runnable接口
//1、定义类实现Runnable接口。
// 2、覆盖接口中的run方法,将线程的任务代码封装到run方法
@Override
public void run() {
for (int i = 0; i < 500; i++) {
System.out.println(i+">>>>>>>>>>>>>>>>>>"+Thread.currentThread().getName());
}
}
}
class TestMyThread2{
public static void main(String[] args) {
MyThread2 d=new MyThread2();
// 3、通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。
Thread t1=new Thread(d);
Thread t2=new Thread(d);
// 4、调用线程对象的start方法开启线程。
t1.start();
t2.start();
}
}
这种方式另外的写法:
public class MyThread3 {
public static void main(String[] args) {
// Runnable匿名类,实现其run()方法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " is running");
}
}).start();
//lambda表达式函数式编程创建,等同于上述代码
new Thread(()->{
System.out.println(Thread.currentThread().getName() + " is running");
}).start();
}
}
实现Runnable接口的好处:
- 因为Java有单继承的局限性(接口可以多实现),所以这一种方法较为常用。
2.3 实现Callable接口
public class MyThread4 implements Callable<Long> {
@Override
public Long call() throws Exception {
return System.currentTimeMillis();
}
}
class TestMyThread4{
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建线程池
ExecutorService pool= Executors.newFixedThreadPool(2);
//执行Runnable对象或者Callable对象代表的线程
Future<Long> f1 = pool.submit(new MyThread4());
Future<Long> f2 = pool.submit(new MyThread4());
Future<Long> f3 = pool.submit(new MyThread4());
Future<Long> f4 = pool.submit(new MyThread4());
//取值
System.out.println(f1.get());
//结束
pool.shutdown();
}
}
- 返回值的定义:Callable定义时,可以使用自定义的类放在T的位置,类里面封装需要的属性;
- 返回值的接收:Future,接收返回值就是用Future了,T就是定义的返回类了,和Callable中的T是同一个;
- 逻辑处理:重写call()方法,return返回值;
- 返回参数的提交:一般是配合线程池来使用,定义一个线程池,submit()调用Callable的call方法,返回结果是Future对象,即便线程还没有结束,对象会先生成;
- 返回值的获取:调用返回对象的get()方法;
实现Callable的优点:
- 可以有返回值;
- 可以抛出异常;