什么是线程
线程是进程内的执行单元
例如 下面36417,就是进程
通过 命令,看到的,就是进程号37417里的线程
jstack 36417
线程的状态
线程的状态,本来想找个图片的,看到百度经验这篇,说得挺好,挺详细,就附上链接吧
https://jingyan.baidu.com/article/f79b7cb33886ef9144023ebf.html
线程的基本操作
创建线程的三种形式
1.直接继承一个Thread类,重写run方法
2.实现Runnable的接口,实现run方法,这种形式,是我平时工作中,使用最多的形式 3.创建一个Future接口的实现类 FutureTask,这种形式有返回值,并且可以抛出异常
需要注意的是,调用start方法,才是执行线程,如果只是执行run方法,那么程序会当成普通方法运行;
代码如下
public class TestThread {
public static void main(String[] args) throws InterruptedException, ExecutionException {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
};
FutureTask<Integer> futureTask = new FutureTask<>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName());
return 10;
}
});
Thread thread = new Thread(futureTask);
Thread thread1 = new Thread() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
};
Thread thread2 = new Thread(runnable);
thread.start();
thread1.start();
thread2.start();
try {
thread.join();
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(futureTask.get());
}
}
线程的一些常见方法:
Thread.stop() 线程终止;不推荐使用,它会释放所有monitor监控,本来运行中的线程,或者运行一半,任务还没有执行完成,也会被终止
public void Thread.interrupt() // 中断线程 public boolean Thread.isInterrupted() // 判断是否被中断 public static boolean Thread.interrupted() // 判断是否被中断,并清除当前中断状态
suspend() ; 挂起;suspend()不会释放锁,如果加锁发生在resume()之前 ,则死锁发生 resume();继续执行
join(); join(long millis);等待线程结束
yeild();谦让;是指空出cpu当前的运行周期,等待下一轮cpu的时间片
守护线程
在后台默默地完成一些系统性的服务,比如垃圾回收线程、JIT线程就可以理解为守护线程
当一个Java应用内,只有守护线程时,Java虚拟机就会自然退出
Thread thredTest = new Thread(() ->{
System.out.println(Thread.currentThread().getName());
}) ;
//标记为守护线程
thredTest.setDaemon(true);
thredTest.start();
线程优先级
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;
Thread high= new Thread(() ->{
System.out.println(Thread.currentThread().getName());
}) ;
Thread low= new Thread(() ->{
System.out.println(Thread.currentThread().getName());
}) ;
high.setPriority(Thread.MAX_PRIORITY);
low.setPriority(Thread.MIN_PRIORITY);
low.start();
high.start();
高优先级的线程更容易再竞争中获胜,更容易获得cpu的临幸
基本的线程同步操作
synchronized
指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。
//实例对象:同步代码块,锁住的该类的实例对象
synchronized(this){
}
//class对象:锁住的该类的类对象
synchronized(Test.class){
}
//任意实例对象:锁住的是该创建的实例对象,下例是对lock对象加锁
Object lock = new Obejct();
synchronized(lock){
}
对方法加锁
//作用在方法上---实例方法:类的对象实例,锁住的是该类的实例对象;
//相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。
public synchronized void test(){
//........
}
//作用在方法上---静态方法:锁住的类的对象;相当于对当前类加锁,进入同步代码前要获得当前类的锁。
public static synchronized void test1(){
//.....
}
Object.wait() Obejct.notify()
首先wait方法和notify方法,是在synchronized关键词中使用的,也就说,在执行方法之前,肯定是获取到了对应的锁操作;
举例说明:A线程执行的时候,会释放当前获取到的锁,让出cpu的执行的时间,让线程进入等待状态,直到B线程获取锁的对象,执行对象的notify方法,才会继续执行;需要注意的时候,notify方法,不会释放锁,只有B线程执行完了,A线程才会继续获取对象锁,继续执行
public static class T1 extends Thread{
public void run(){
synchronized (object) {
System.out.println(System.currentTimeMillis()+":T1 start! ");
try {
System.out.println(System.currentTimeMillis() +":T1 wait for object ");
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis()+":T1 end!");
}
}
public static class T2 extends Thread{
public void run(){
synchronized (object) {
System.out.println(System.currentTimeMillis() +":T2 start! notify one thread");
object.notify(); System.out.println(System.currentTimeMillis()+":T2 end!");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
} }
}
最终的执行结果的顺序,也是可以看出来的
1566523411000:T1 start!
1566523411000:T1 wait for object
1566523411000:T2 start! notify one thread
1566523411000:T2 end!
1566523411000:T1 end!
Happen-Before
程序顺序原则:一个线程内保证语义的串行性
volatile规则:volatile变量的写,先发生于读,这保证了volatile变量的可见性
锁规则:解锁(unlock)必然发生在随后的加锁(lock)前
传递性:A先于B,B先于C,那么A必然先于C
线程的start()方法先于它的每一个动作
线程的所有操作先于线程的终结(Thread.join())
线程的中断(interrupt())先于被中断线程的代码
对象的构造函数执行结束先于finalize()方法