进程:程序运行资源分配的最小单位,进程内部有多个线程,会共享这个进程的资源
线程:CPU调度的最小单位,必须依赖进程而存在。
并行:同一时刻,可以同时处理事情的能力
并发:与单位时间相关,在单位时间内可以处理事情的能力
1.继承Thread类
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("继承Thread类创建线程");
}
public static void main(String[] args) {
Thread myThread=new MyThread();
myThread.start();
}
}
2.实现Runnable接口
public class MyThread implements Runnable {
@Override
public void run() {
System.out.println("实现Runnable接口创建线程");
}
public static void main(String[] args) {
Thread thread=new Thread(new MyThread());
thread.start();
}
}
3.实现Callable接口
public class MyThread implements Callable {
@Override
public Object call() throws Exception {//有返回值
System.out.println("实现Callable接口创建线程");
return "result";
}
public static void main(String[] args) throws Exception{
FutureTask futureTask=new FutureTask(new MyThread());
Thread thread=new Thread(futureTask);
thread.start();
System.out.println(futureTask.get());
}
}
4.线程池
public static void main(String[] args) throws Exception{
ExecutorService executor= Executors.newCachedThreadPool();
executor.submit(new Runnable() {
@Override
public void run() {
try {
System.out.println("通过线程池创建线程");
} catch (Exception e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
}
});
}
注:Runnable与接口Callable区别
Callable规定的方法是call(),Runnable规定的方法是run()
Callable的任务执行后可返回值,而Runnable的任务是不能返回值得
stop () 已废弃,因为stop ()会导致线程不会正确释放资源
resume () 继续 和 suspend ()挂起 已废弃,suspend ()容易导致死锁。
interrupt() 和 isInterrupted() 调用一个线程的interrupt() 方法中断一个线程,并不是强行关闭这个线程,只是跟这个线程打个招呼,将线程的中断标志位置为true,线程是否中断,由线程本身决定。isInterrupted() 判定当前线程是否处于中断状态。java线程是协作式,而非抢占式
interrupted() 是static方法,判定当前线程是否处于中断状态,同时中断标志位改为false。
注:方法里如果抛出InterruptedException,线程的中断标志位会被复位成false,如果确实是需要中断线程,要求我们自己在catch语句块里再次调用interrupt()。
新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态。
线程只有5种状态。整个生命周期就是这几种状态的切换。
run方法就是普通对象的普通方法
只有调用了start()后,Java才会将线程对象和操作系统中实际的线程进行映射,再来执行run方法。
取值为1~10,缺省为5,但线程的优先级不可靠,不建议作为线程开发时候的手段
守护线程与普通线程的唯一区别是:当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;如果还有一个或以上的非守护线程则不会退出。
守护线程中finally不能保证一定执行
对象锁,锁的是类的对象实例 。多次new实例对象,分别调用加锁的方法是并行的,只有是同一个对象多次调用加锁方法才会存在竞争,spring缺省是单例的,对象是唯一的。
类锁 ,锁的是每个类的的Class对象,每个类的的Class对象在一个虚拟机中只有一个,所以类锁也只有一个。
volatile变量的读写对所有线程立即可见只是读和写一步,复杂的运算不能保证对其他线程可见,因为复杂的运算可能会被编译成多条指令,JMM只保证,volatile变量从工作内存写回到主内存是对其他线程可见的。
谈到volatile,理解原子性和易变性是不同的概念这一点很重要,volatile是轻量级的锁,它只具备可见性,但没有原子特性。如果你将一个域声明为volatile,那么只要对这个域产生了写操作,所有的读操作都可以看到这个修改,即便使用了本地缓存也一样,volatile会被立即写入到主内存中,而读的操作就发生在主内存中。在非volatile域上的原子操作不必刷新到主内存中,所以读操作的任务看不到这个值,如果多个任务在同时访问某个域,那么这个域就应该是volatile,否则这个域就应该经过同步来访问,同步也会导致向主内存中刷新。使用volatile而不是synchronized的唯一安全的情况就是类中只有一个可变的域。个人认为,第一选择应该是synchronized,这应该最安全的方式如果并发水平不高,最好还是不要使用。
提枪策马乘胜追击04-21 20:01
代码小兵92504-17 16:07
代码小兵98804-25 13:57
杨晶珍05-11 14:54