1、线程简介
(1)线程是操作系统调度的最小单元;
(2)在一个进程里可以创建多个线程,这些线程都有各自的计数器、堆栈和局部变量等属性,并且能够访问共享的内存变量;
(3)一个程序作为一个进程来运行,程序运行过程中可以创建多个线程;
(4)一个线程在一个时刻只能运行在一个处理器上,多线程程序可以充分利用多处理器执行任务;
(5)线程优先级:线程优先级决定线程需要多或者少分配处理器资源的线程属性;(有些操作系统会忽略对线程优先级的设定,使其无效);
2、线程的状态
3、新建一个线程的方式
(1)继承Thread,重写run方法
(2)实现Runnable,接口重写run方法
4、Daemon线程
Daemon线程是一种支持型线程,作为后台调度以及支持性工作,当java虚拟机中不存在非Deamon线程的时候,java虚拟机将会退出(即当只剩下Daemon线程的时候,jvm将退出,最终Daemon线程也将终止);Daemon线程可以通过thread.setDaemon(true)
实现
5、中断interrupt
线程中断是一种软性的停止线程的机制,(thread.interrupt()
)它并不会立即终止线程;而是通知被中断线程“希望”该线程尽快停止,否则可能造成在修改某个对象的时候被强制终止并释放锁,读线程会读到一个未完全初始化的该对象。(正确合理的终止一个线程应该采用interrupt()方法,而不是强制性使用stop())
6、volatile和synchronized关键字
(1)volatile
关键字volatile可以用来修饰成员变量,告诉程序任何对该变量的访问都要从共享内存中获取,并且对它的改变必须同步刷新回共享内存中,它保证了所有线程对该变量访问的可见性;任何对该变量的访问和修改都以共享内存为主(线程间通过共享内存的方式通信)
(2)synchronized
关键字synchronized可以修饰方法或者同步块的形式使用,主要确保多个线程在同一时刻,只能有一个线程处于方法或者同步块中,保证了线程对变量访问的可见性和排他性
7、等待通知机制
(1)使用wait()、notify()和notifyAll()时需要先对调用对象加锁
(2)notify()和notifyAll()方法调用后,等待线程依旧不会从wait()方法返回,需要调用notify()和notifyAll()的线程释放锁后,等待线程才有机会从wait()返回
(3)notify()方法将等待队列中的一个线程移到同步队列;notifyAll()方法将等待队列中的所有线程移到同步队列;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class WaitNotify {
static boolean flag = true;
static Object lock = new Object();
public static void main(String[] args) throws Exception{
Thread waitThread = new Thread(new Wait(),"WaitThread");
waitThread.start();
TimeUnit.SECONDS.sleep(1);
Thread notifyThread = new Thread(new Notify(),"NotifyThread");
notifyThread.start();
}
static class Wait implements Runnable {
@Override
public void run() {
// 加锁,拥有lock的Monitor
synchronized(lock) {
// 当条件不满足时,继续wait,同时释放了lock的锁
while(flag) {
try {
System.out.println(Thread.currentThread()+"flag is true. wait @ "+
new SimpleDateFormat("HH:mm:ss").format(new Date()));
lock.wait();
}catch (InterruptedException e) {
}
}
// 当条件满足时,完成工作
System.out.println(Thread.currentThread()+"flag is false. running @ "+
new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
}
}
static class Notify implements Runnable {
@Override
public void run() {
// 加锁,拥有lock的Monitor
synchronized(lock) {
// 获得lock的锁,然后进行通知,通知时不会释放lock的锁,
// 直到当前线程释放了lock后,WaitThread才能从wait方法中返回
System.out.println(Thread.currentThread()+"hold lock. notify @ "+
new SimpleDateFormat("HH:mm:ss").format(new Date()));
lock.notifyAll();
flag = false;
SleepUtils.second(5);
}
// 再次加锁
synchronized (lock) {
System.out.println(Thread.currentThread()+"hold lock. again. sleep @ "+
new SimpleDateFormat("HH:mm:ss").format(new Date()));
SleepUtils.second(5);
}
}
}
}
class SleepUtils {
public static final void second(long seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
}catch (InterruptedException e) {
}
}
}
输出:
>>> Thread[WaitThread,5,main]flag is true. wait @ 23:23:29
>>> Thread[NotifyThread,5,main]hold lock. notify @ 23:23:30
>>> Thread[NotifyThread,5,main]hold lock. again. sleep @ 23:23:35
>>> Thread[WaitThread,5,main]flag is false. running @ 23:23:40
8、Thread.join()的使用
一个线程A执行了thread.join()语句(如果是主线程,则是main()中执行thread.join()语句,如果是子线程,则是run()中执行thread.join()语句),其含义是:当前线程A等待thread线程终止之后,才从thread.join()返回
9、yield()方法的使用
作用:暂停当前正在执行的线程对象。
yield()方法是停止当前线程,让同等优先权的线程或更高优先级的线程有执行的机会。如果没有的话,那么yield()方法将不会起作用,并且由可执行状态后马上又被执行。
10、wait()和sleep()方法的区别(有没释放锁)
sleep方法没有释放锁;
wait方法释放了锁,使得其他线程可以使用同步控制块或者方法(锁代码块和方法锁)
参考
《Java并发编程的艺术》
https://www.cnblogs.com/loren-Yang/p/7538482.html