1.进程和线程的区别是什么?
进程:进程是执行着的应用程序,如手机上的一个应用
线程:线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。
进程与线程的关系:
1.线程是在进程中执行的一个任务,他可以共享进程中的资源。线程可以被称为轻量级进程,它在进程中进行创建和销毁线程相比于进程的创建和销毁需要较少的资源和花销。
2.进程是操作系统进行资源分配的基本单位,而线程是操作系统进行调度的基本单位。
2.创建线程有几种不同的方式?
1.继承Thread类创建线程
/**
* 通过继承Thread实现run方法
*/
public class Actor extends Thread{
@Override
public void run(){
System.out.println(getName()+"是一个演员!");
int count=0;
boolean keepRunning=true;
while(keepRunning){
System.out.println(getName()+"登台演出:"+ (++count));
if(count==100){
keepRunning=false;
}
if(count%10==0){
try {
//当前线程休眠,其他线程仍将执行
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println(getName()+"的演出结束了!");
}
public static void main(String[] args) {
//启动线程通过继承Thread
Thread actor=new Actor();
actor.setName("Mr. Thread");
actor.start();
// //启动线程通过实现Runnable接口
// Thread actressThread=new Thread(new Actress(),"Ms. Runnable");
// actressThread.start();
}
}
2.实现Runnable接口创建线程
/**
* 通过实现Runnable接口实现run方法
*/
class Actress implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"是一个演员!");
int count = 0;
boolean keepRunning = true;
while(keepRunning){
System.out.println(Thread.currentThread().getName()+"登台演出:"+ (++count));
if(count == 100){
keepRunning = false;
}
if(count%10== 0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
System.out.println(Thread.currentThread().getName()+"的演出结束了!");
}
public void sing(){
System.out.println("haha");
}
}
用这个实例作为Thread的target来创建Thread对象,这个Thread对象才是真正的线程对象。
public static void main(String[] args) {
// //启动线程通过继承Thread
// Thread actor=new Actor();
// actor.setName("Mr. Thread");
// actor.start();
//启动线程通过实现Runnable接口
Thread actressThread=new Thread(new Actress(),"Ms. Runnable");
actressThread.start();
}
3.通过Callable和Future创建线程
package com.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableThreadTest implements Callable<Integer>
{
public static void main(String[] args)
{
CallableThreadTest ctt = new CallableThreadTest();
FutureTask<Integer> ft = new FutureTask<>(ctt);
for(int i = 0;i < 100;i++)
{
System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);
if(i==20)
{
new Thread(ft,"有返回值的线程").start();
}
}
try
{
System.out.println("子线程的返回值:"+ft.get());
} catch (InterruptedException e)
{
e.printStackTrace();
} catch (ExecutionException e)
{
e.printStackTrace();
}
}
@Override
public Integer call() throws Exception
{
int i = 0;
for(;i<100;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
}
return i;
}
}
@see http://blog.csdn.net/sinat_34814635/article/details/78959162
3.线程的几种状态?
3.1 状态含义解释
线程一共有6种状态。
源码如下:
/**
* A thread state. A thread can be in one of the following states:
* <ul>
* <li>{@link #NEW}<br>
* A thread that has not yet started is in this state.
* </li>
* <li>{@link #RUNNABLE}<br>
* A thread executing in the Java virtual machine is in this state.
* </li>
* <li>{@link #BLOCKED}<br>
* A thread that is blocked waiting for a monitor lock
* is in this state.
* </li>
* <li>{@link #WAITING}<br>
* A thread that is waiting indefinitely for another thread to
* perform a particular action is in this state.
* </li>
* <li>{@link #TIMED_WAITING}<br>
* A thread that is waiting for another thread to perform an action
* for up to a specified waiting time is in this state.
* </li>
* <li>{@link #TERMINATED}<br>
* A thread that has exited is in this state.
* </li>
* </ul>
*
* <p>
* A thread can be in only one state at a given point in time.
* These states are virtual machine states which do not reflect
* any operating system thread states.
*
* @since 1.5
* @see #getState
*/
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.
*/
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): 在调用thread.start()方法后,就变成了Runnable状态。Runnable状态其实包含了可运行和正在运行的两种状态
被阻塞状态(Blocked):等待获取锁或未获取到锁,线程无法得到执行。
等待(Waiting): 线程等待另一个线程通知调度器一个条件时,该线程处于waiting状态。如调用object.wait()或者thread.join()方法后。
计时等待(timed waiting):设置了等待参数。当过了设置的超时时间,则又会转为可运行状态。
被终止(TERMINATED):线程完成了run()方法的执行而正常终止或者执行run()方法过程中抛出异常。
3.2 状态互相转换关系
备注:可以调用thread.getState()来查看线程的状态。
为了便于理解,在将各个状态进行如下拆分,其中的关系参考如图:
备注:调用join或者sleep方法后,线程是处于waiting或timed waiting状态。
状态解释:
初始状态:线程刚刚创建,即处于初始状态,此状态线程还不能够运行。
可运行状态:线程准备运行,不一定立马就能开始执行。要被调度中心选中之后才能运行。
运行中(Running):进程正在执行线程的代码。即在执行run()方法.
3.3 生命周期
当我们在Java程序中新建一个线程时,它的状态是New。当我们调用线程的start()方法时,状态被改变为Runnable。线程调度器会为Runnable线程池中的线程分配CPU时间并且将它们的状态改变为Running。
可参看下图理解
参考:线程生命周期 https://www.journaldev.com/1044/thread-life-cycle-in-java-thread-states-in-java
4.什么是线程调度器(Thread Scheduler)和时间分片(Time Slicing)?
线程调度器:
线程调度器是一个操作系统服务,它负责为Runnable状态的线程分配CPU时间。一旦我们创建一个线程并启动它,它的执行便依赖于线程调度器的实现。
线程调度并不受到Java虚拟机控制,所以由应用程序来控制它是更好的选择(也就是说不要让你的程序依赖于线程的优先级。
时间分片:时间分片是指将可用的CPU时间分配给可用的Runnable线程的过程。
5.thread类常用到的方法:
1、public static void yield()
暂停当前正在执行的线程对象,并执行其他线程(也有可能会执行到自己这个线程)。
2.public final void join()
等待该线程终止。
1)join是Thread类的一个方法,启动线程后直接调用,即join()的作用是:“等待该线程终止”,这里需要理解的就是该线程是指的主线程等待子线程的终止。也就是在主线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。
2)为什么要用join()方法
- 在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。
3.public static void sleep(long millis) throws InterruptedException
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。
注意:sleep方法不会释放自己的同步锁,这是和object.wait()方法的最大区别。
4. interrupted():测试 当前线程 是否已经是中断状态,执行后会清除当前线程的中断标记位。
5.isInterrupted():测试线程 Thread 对象 是否已经是中断状态,但不清除状态标志。
sleep和sleep(0)的区别。
Sleep 接口均带有表示睡眠时间长度的参数 timeout。调用以上提到的 Sleep 接口,会有条件地将调用线程从当前处理器上移除,并且有可能将它从线程调度器的可运行队列中移除。这个条件取决于调用 Sleep 时timeout 参数。
当 timeout = 0, 即 Sleep(0),如果线程调度器的可运行队列中有大于或等于当前线程优先级的就绪线程存在,操作系统会将当前线程从处理器上移除,调度其他优先级高的就绪线程运行;如果可运行队列中的没有就绪线程或所有就绪线程的优先级均低于当前线程优先级,那么当前线程会继续执行,就像没有调用 Sleep(0)一样。
当 timeout > 0 时,如:Sleep(1),会引发线程上下文切换:调用线程会从线程调度器的可运行队列中被移除一段时间,这个时间段约等于 timeout 所指定的时间长度。为什么说约等于呢?是因为睡眠时间单位为毫秒,这与系统的时间精度有关。通常情况下,系统的时间精度为 10 ms,那么指定任意少于 10 ms但大于 0 ms 的睡眠时间,均会向上求值为 10 ms。
而调用 SwitchToThread() 方法,如果当前有其他就绪线程在线程调度器的可运行队列中,始终会让出一个时间切片给这些就绪线程,而不管就绪线程的优先级的高低与否。
结论:
由上面的分析可以看出,如果我们想让当前线程真正睡眠一下子,最好是调用 Sleep(1) 或 SwitchToThread()。
6.object类中的wait()\notify()\notifyAll()方法
1)public final void wait()
在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
注意:wait方法会释放自己的同步锁,也就是其他线程可以进入被锁住的方法。
2)public final void notify()和public final void notifyAll()
notify():唤醒在此对象监视器上等待的单个线程
notifyAll():唤醒在此对象监视器上等待的所有线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争,即具体会执行哪一个线程是不确定。
执行完notify()或者notifyAll()方法后,该线程如果拿到了同步锁就会变成可运行状态(Runnable)。
线程之间的通信也主要是通过wait()\notify()\notifyAll()方法来完成的。
8.多线程编程的特点
1.优点
在多线程程序中,多个线程被并发的执行以提高程序的效率,CPU不会因为某个线程需要等待资源而进入空闲状态。
如果是单线程的话:
单线程在执行遇到一些io操作会进行等待状态,CPU就没有资源去执行其他请求了。
2.可能会存在的问题
- 并发问题
- 资源占有问题,可能消耗CPU的资源
9.用户线程和守护线程有什么区别?
1.当我们在Java程序中创建一个线程,它就被称为用户线程。
2.守护线程是指在程序运行的时候在后台提供一种通用服务的线程。典型的守护线程如垃圾回收线程。
如果JVM中所有的线程都是守护线程,那么JVM就会退出,进而守护线程也会退出。
守护线程是依赖于用户线程,用户线程退出了,守护线程也就会退出,典型的守护线程如垃圾回收线程。
用户线程是独立存在的,不会因为其他用户线程退出而退出。
一个守护线程创建的子线程依然是守护线程。
10.在多线程中,什么是上下文切换(context-switching)?
上下文切换是存储和恢复CPU状态的过程,它使得线程执行能够从中断点恢复执行。上下文切换是多任务操作系统和多线程环境的基本特征。
11.什么是竞态条件?
当两个线程竞争同一资源时,如果对资源的访问顺序敏感,就称存在竞态条件。
导致竞态条件发生的代码区称作临界区。
在临界区中使用适当的同步就可以避免竞态条件。
临界区实现方法有两种,一种是用synchronized,一种是用Lock显式锁实现。
@see 什么是竞态条件? 举个例子说明。 https://blog.csdn.net/Roger_CoderLife/article/details/83148318
12.Java中如何停止一个线程?
Java提供了很丰富的API但没有为停止线程提供API。JDK 1.0本来有一些像stop(), suspend() 和 resume()的控制方法但是由于潜在的死锁威胁因此在后续的JDK版本中他们被弃用了,之后Java API的设计者就没有提供一个兼容且线程安全的方法来停止一个线程。当run() 或者 call() 方法执行完的时候线程会自动结束,
1.使用共享变量的方式
如果要手动结束一个线程,你可以用volatile 布尔变量来退出run()方法的循环
2.使用interrupt方法终止线程
该方法虽然不会中断一个正在运行的线程,但是它可以使一个被阻塞的线程抛出一个中断异常,从而使线程提前结束阻塞状态,退出堵塞代码。
@see java如何正确停止一个线程 https://www.cnblogs.com/luckygxf/p/4737655.html
参考资料:
1.《core java》
2.https://www.cnblogs.com/dolphin0520/p/3932934.html