线程状态
在Thread.State 中关于线程状态的解释
NEW
Thread state for a thread which has not yet started.
RUNNABLE
Thread state for a runnable thread.
A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.
BLOCKED
Thread state for a thread blocked waiting for a monitor lock.
A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling Object.wait().
WAITING
Thread state for a waiting thread.
A thread is in the waiting state due to calling one of the following methods:
Object.wait()with no timeout
Thread.join() with no timeout
LockSupport.park()
A thread in the waiting state is waiting for another thread to perform a particular action.
For example, a thread that has called Object.wait() on an object is waiting for another thread to call Object.notify() or Object.notifyAll() on that object. A thread that has called Thread.join() is waiting for a specified thread to terminate.
TIMED_WAITING
Thread state for a waiting thread with a specified waiting time.
A thread is in the timed waiting state due to calling one of the following methods with a specified positive waiting time:
Thread.sleep
Object.wait(long)with timeout
Thread.join(long)with timeout
LockSupport.parkNanos
LockSupport.parkUntil
TERMINATED
Thread state for a terminated thread.
The thread has completed execution.
线程优先级
每个线程都有一个优先级以便操作系统确定线程的调度顺序
根据Thrad类初始化方法,每个线程在初始化时都会从当前线程中取出一些属性来设置给自身,其中包括线程的priority。在Thread中同时定义有NORM_PRIORITY默认优先级5,以及MIN_PRIORITY最小1,MAX_PRIORITY最大10
较高优先级的线程会在低优先级的线程之前分配处理器资源。但是,线程优先级不能保证线程执行的顺序
线程创建
三种创建线程的方法:
实现Runnable接口
继承Thread类
通过 Callable 和 Future 创建线程
实现Runnable接口创建线程
创建类实现Runnable接口,实现run 方法
public class MyThreadImplRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + Thread.currentThread().getState());
for (int i = 0 ; i < 100 ;i++) {
System.out.println(Thread.currentThread().getName() + "-" + i);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "exit");
}
}
创建启动线程
public static void main(String[] args) {
Thread t1 = new Thread(new MyThreadImplRunnable(),"thread1");
System.out.println("thread1" + t1.getState());
t1.start();
Thread t2 = new Thread(new MyThreadImplRunnable(),"thread2");
System.out.println("thread2" + t2.getState());
t2.start();
}
执行结果
thread1NEW
thread2NEW
thread1RUNNABLE
thread1-0
thread2RUNNABLE
thread2-0
thread1-1
thread2-1
thread2-2
thread1-2
thread1-3
thread2-3
thread1-4
thread2-4
thread1exit
thread2exit
继承Thread创建线程
创建类来继承Thread,实现run方法
public class MyThreadExtThread extends Thread {
public MyThreadExtThread(String threadName) {
super(threadName);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + Thread.currentThread().getState());
for (int i = 0 ; i < 5 ;i++) {
System.out.println(Thread.currentThread().getName() + "-" + i);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "exit");
}
}
启动线程
public static void main(String[] args) {
Thread t1 = new MyThreadExtThread("thread1");
System.out.println("thread1" + t1.getState());
t1.start();
Thread t2 = new MyThreadExtThread("thread2");
System.out.println("thread2" + t2.getState());
t2.start();
}
执行结果
thread1NEW
thread2NEW
thread1RUNNABLE
thread1-0
thread2RUNNABLE
thread2-0
thread1-1
thread2-1
thread2-2
thread1-2
thread1-3
thread2-3
thread1-4
thread2-4
thread1exit
thread2exit
通过 Callable 和 Future 创建线程
创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。
public class MyCallable implements Callable {
@Override
public Integer call() throws Exception {
int sum = 0 ;
for (int i = 0 ; i < 100;i++) {
sum += i;
}
return sum;
}
}
创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。配合ExecutorService 启动使用线程,调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值
public static void main(String[] args) {
MyCallable myCallable = new MyCallable();
FutureTask futureTask = new FutureTask<>(myCallable);
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.submit(futureTask);
try {
System.out.println(futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
在执行线程测试的时候发现一个有趣的现象,使用junit进行测试时,有时能够执行完达到预期的效果,有时并不能。
经过百度后发现原来Junit只管自己的运行,就是说当Junit执行完毕后,就会关闭程序,不会关心是否还有自己启动的后台线程在运行。当Junit运行完毕后,如果后台线程还没有执行完毕,那么也是不会再执行了
创建线程的三种方式的对比
采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。
使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。
Runnable、Thread 这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果。
Thread 类的方法
序号
方法描述
1
public void start()
使该线程开始执行;
Java 虚拟机调用该线程的 run 方法。
2
public void run()
如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;
否则,该方法不执行任何操作并返回。
3
public final void setName(String name)
改变线程名称,使之与参数 name 相同。
4
public final void setPriority(int priority)
更改线程的优先级。
5
public final void setDaemon(boolean on)
将该线程标记为守护线程或用户线程。
6
public final void join(long millisec)
等待该线程终止的时间最长为 millis 毫秒。
7
public void interrupt()
中断线程。
8
public final boolean isAlive()
测试线程是否处于活动状态。
Thread类的静态方法
序号
方法描述
1
public static void yield()
暂停当前正在执行的线程对象,并执行其他线程。
2
public static void sleep(long millisec)
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
3
public static boolean holdsLock(Object x)
当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。
4
public static Thread currentThread()
返回对当前正在执行的线程对象的引用。
5
public static void dumpStack()
将当前线程的堆栈跟踪打印至标准错误流。
线程睡眠 -- 使用sleep方法之后,线程进入阻塞状态,只有当睡眠的时间结束,才会重新进入到就绪状态,而就绪状态进入到运行状态,是由系统控制的,我们不可能精准的去干涉它,所以如果调用Thread.sleep(1000)使得线程睡眠1秒,可能结果会大于1秒.
线程让步 -- yield让正在执行的线程暂停,但是不会进入阻塞状态,而是直接进入就绪状态
并行与并发
并发是两个任务可以在重叠的时间段内启动,运行和完成。并行是任务在同一时间运行,例如,在多核处理器上。
并发是独立执行过程的组合,而并行是同时执行(可能相关的)计算。
并发是一次处理很多事情,并行是同时做很多事情。
应用程序可以是并发的,但不是并行的,这意味着它可以同时处理多个任务,但是没有两个任务在同一时刻执行。
应用程序可以是并行的,但不是并发的,这意味着它同时处理多核CPU中的任务的多个子任务。
一个应用程序可以即不是并行的,也不是并发的,这意味着它一次一个地处理所有任务。
应用程序可以即是并行的也是并发的,这意味着它同时在多核CPU中同时处理多个任务。
网上看到的关于并发与并行的区别,觉得描述的挺生动
个人理解:
并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
并发:交替做不同事情的能力,即不同的代码块交替执行
并行:同时做不同事情的能力,不同的代码块同时执行
为什么要用多线程
为了更好的利用cpu的资源,如果只有一个线程,则第二个任务必须等到第一个任务结束后才能进行,如果使用多线程则在主线程执行任务的同时可以执行其他任务,而不需要等待;
进程之间不能共享数据,线程可以;
系统创建进程需要为该进程重新分配系统资源,创建线程代价比较小;
sleep 和wait 的区别
区别
sleep
wait
所属类
是Thread类的方法
是Object类的方法
时间
必须指定时间
wait可以指定时间也可以不指定时间
释放锁
释放CPU执行权不释放锁
释放CPU执行权也释放锁
使用地方
任意地方
只能在同步代码方法或同步代码块中使用