线程相关基本概念
进程
内存中独立运行的应用程序,在window的任务管理器中可以找到进程。
线程
进程中的一个执行任务,控制单元,在程序中独立运行。
多线程
程序中包含多个执行流,一个程序中可以同时运行多个线程来执行不同的任务。
用户线程
运行在前台的具体执行的任务。
守护线程
为用户线程服务的程序。
并发编程的三个必要因素
原子性:也是事务的一个特性之一,是指一个或者多个操作要么全部成功,要么全部失败。
可见性:线程之间的共享资源的变化,其他线程可以看到。
有序性:程序执行的顺序按照代码的先后顺序执行。
线程死锁
死锁的产生条件是先需要有共享资源,各个线程为了竞争共享资源造成的阻塞,为了得到共享资源循环等待,造成系统产生了死锁。
死锁的形成的条件
- 互斥条件:共享资源只能一个线程占用,其他线程如果想要得到共享资源,必须等待占用资源的线程释放。
2.请求保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
3.不可剥夺条件:不能得到其他线程占用的共享资源。
4.环路条件:若干进程之间形成一种头尾相接的循环等待资源关系。
线程死锁的处理
线程死锁的处理必须要破坏线程死锁形成的四个必要条件之一。
1.避免一个线程同时获得多个锁。
2.避免一个线程在锁内占用多个资源,尽量保证每个锁只占用一个资源。
3.尝试使用定时锁检测,或者不到锁自动再次尝试不要循环等待。
线程的生命周期
图来自于菜鸟教程:
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;
}
线程创建的四种方式
1.继承Thread
/**
* 创建现线程的第一种方式
* 1、继承线程类
*/
public class FirstThread extends Thread{
@Override
public void run(){
System.out.println(Thread.currentThread().getName()+"运行run方法...");
}
}
2.实现runable接口
/**
* 创建线程的第二种方式
* 实现接口Runnable
*/
public class SecondThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"运行run方法...");
}
}
3.实现callable接口
/**
* 创建线程的第三种方法
* 实现callable接口
*/
public class ThirdThread implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println(Thread.currentThread().getName()+"运行run方法...");
return "执行成功!";
}
}
4.实现匿名内部类以及lamda创建
/**
* 使用匿名内部类创建方式
*/
public class FourThread {
public static void main(String[] args) {
//1.继承Thread实现
Thread thread1 = new FirstThread();
thread1.start();
//2.实现Runable接口
Thread thread2 = new Thread(new SecondThread());
thread2.start();
//3.实现callable接口
FutureTask task = new FutureTask(new ThirdThread());
Thread thread3 = new Thread(task);
thread3.start();
//创建线程
Thread thread4 = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0 ;i < 5;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
});
thread4.start();
//还可以使用java8新特性创建lambda
Thread thread5 = new Thread(()->{
System.out.println(Thread.currentThread().getName()+":使用lambda创建线程");
});
thread5.start();
}
}
线程提供的方法
-
wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁;
-
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理InterruptedException 异常;
/**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds, subject to
* the precision and accuracy of system timers and schedulers. The thread
* does not lose ownership of any monitors.
*
* @param millis
* the length of time to sleep in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public static native void sleep(long millis) throws InterruptedException;
- notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由 JVM 确定唤醒哪个线程,而且与优先级无关;
- notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;
简单的例子实现线程控制
使用wait和notify控制两个线程交替输出打印。
public class WaitNotifyDemo {
public static void main(String[] args) {
final Object o =new Object();
char[] nums = "1234".toCharArray();
char[] chars = "ABCD".toCharArray();
new Thread(()->{
//加锁
synchronized (o){
for (char n:nums){
System.out.print(n);
try {
o.notify();//唤醒其他线程
o.wait();//释放锁
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//叫醒其他线程
o.notify();
}
},"t1").start();
new Thread(()->{
synchronized (o) {
for (char c : chars) {
System.out.print(c);
try {
o.notify();
o.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
o.notify();
}
},"t2").start();
}
}