在学习JUC之前,我们需要了解下进程和线程的概念,以及并发和并行的区别。
1、进程与线程:
- 进程:一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,比如在Windows系统中,一个运行的xx.exe就是一个进程。由数据+代码+pcb(进程控制块)组成,一个进程往往至少包含一个线程。
- 线程:是进程中的实际运作单位,假如我们使用qq聊天,发送信息的功能就是一个线程,也能收到信息功能也是一个线程。进程中的一个执行任务(控制单元),负责当前进程中程序的执行。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可共享数据。
Tip:Java默认是拥有两个线程,main和GC(垃圾回收)线程。
对于Java而言,我么 可以使用Thread,Runnable,Callable进行创建线程。
我们思考一个问题,Java真的可以开启线程吗?
答案是不行的,我们进入Thread类查看一下源码:
/**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the <code>run</code> method of this thread.
* <p>
* The result is that two threads are running concurrently: the
* current thread (which returns from the call to the
* <code>start</code> method) and the other thread (which executes its
* <code>run</code> method).
* <p>
* It is never legal to start a thread more than once.
* In particular, a thread may not be restarted once it has completed
* execution.
*
* @exception IllegalThreadStateException if the thread was already
* started.
* @see #run()
* @see #stop()
*/
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* 这个方法不会被主线方法线程或“系统”调用。
* group threads created/set up by the VM. Any new functionality added
* 将虚拟机创建/设置的线程分组。添加的任何新功能
* to this method in the future may have to also be added to the VM.
*到这个方法以后可能也要添加到VM。
* A zero status value corresponds to state "NEW".
* 零状态值对应状态“NEW”。
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
*通知组该线程即将启动
* so that it can be added to the group's list of threads
* 以便它可以被添加到组的线程列表中
* and the group's unstarted count can be decremented.
* 和组的未启动计数可以减少。 */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
什么也不做。如果start0抛出一个Throwable,那么
it will be passed up the call stack
它将被向上传递到调用堆栈 */
}
}
}
//这是一个C++底层,Java是没有权限操作底层硬件的
private native void start0();
Java是没有权限去开启线程、操作硬件的,这是一个native的一个本地方法,它调用的底层的C++代码。
2、并发和并行
- 并发:在单核的CPU中,我们要同时运行多个进程,多个程序之间的运行是交替执行的,由于切换的速度很快,从我们用户角度来看,这是一个同时进行的过程,但是微观上是交替执行的。
- 并行:CPU多核,多个进程可以同一时刻同时执行。
我们可以通过Java查看当前计算机CPU的核心数:
public class Test {
public static void main(String[] args) {
System.out.println(Runtime.getRuntime().availableProcessors());
}
}
线程的6种状态:
public enum State {
/**
* Thread state for a thread which has not yet started.
* 尚未启动的线程的线程状态。
*/
NEW,
/**
* 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.
* 可运行线程的线程状态。可运行程序中的线程
* 状态在Java虚拟机中执行,但它可能
* 等待操作系统提供的其他资源
* 例如处理器。
*/
RUNNABLE,
/**
* 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
* 等待监视器锁而阻塞的线程的线程状态。
* 处于阻塞状态的线程正在等待监视器锁
* 输入同步块/方法或
* 调用后重新输入同步块/方法
*{@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* 等待线程的线程状态。
* 线程由于调用其中一个线程而处于等待状态
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
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:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
* 终止线程的线程状态。
* 线程已经完成执行。
*/
TERMINATED;
}
线程状态 | |
---|---|
NEW(新建) | 线程尚未启动 |
RUNNABLE(运行) | 线程可以运行 |
BLOCKED(阻塞) | 线程阻塞 |
WAITING(死等) | 线程等待 |
TIMED_WAITING(过时不等) | 有指定时间的线程等待 |
TERMINATED(消亡) | 线程终止 |
wait()和sleep()的区别
1、来自于不同的类:
wait来自于Object类,而sleep属于Thread类
在企业中一般使用以下方式休眠:
//来自于import java.util.concurrent.TimeUnit包
TimeUnit.DAYS.sleep(1); //休眠一天
TimeUnit.SECONDS.sleep(1); //休眠一秒
可以根据单位的选择指定休眠的时长。
2、锁的释放:
wait方法会释放锁。
- wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行。wait()方法可以中断线程的运行,使本线程等待,暂时让出CPU的使用权,并允许其他线程使用这个同步方法。
sleep()方法并不会释放锁。
- 如果当前线程进入了同步锁,sleep()方法并不会释放锁。即使当前线程使用sleep方法让出了cpu,但其他被同步锁挡住了的线程也无法得到执行。
3、使用范围不同
wait:必须在同步代码块中使用
sleep:可以在任何地方使用
总结:
wait | sleep | |
---|---|---|
同步 | wait只能在同步上下文中使用,否则会抛出IllegalMonitorStateException异常 | sleep不用在同步代码块中调用,必须处理异常 |
作用对象 | wait方法定义在Object类中,作用于对象本身 | sleep属于Thread的方法,作用于当前线程 |
释放锁资源 | 是 | 否 |
唤醒条件 | 其他线程调用notify()或者notifyAll()方法 | 超时或者调用interrupt()方法体 |
方法属性 | wait是实例方法 | sleep是静态方法 |