进程与线程的区别
进程:系统正在运行的一个应用程序,程序一旦运行就是进程,进程是资源分配的最小单位
线程:线程是程序执行的最小单位
线程的基本状态
1)new 新建
2)runnable 准备就绪
3)blocked 阻塞
4)waiting 不见不散的等待
5)timed_waiting 过时不候
6)terminated 终结
wait和sleep的区别
1)sleep是Thread的静态方法,wait是Object的方法,任何对象都能够调用
2)sleep不会释放锁,也不需要占用锁。wait会释放锁,但调用它的前提是当前线程占有锁
3)他们都可以被interrupted中断
并发和并行
并发:同一时刻多个线程在访问同一个资源
并行:多项工作一起同时执行
管程 (Monitor)
是一种同步机制,保证同一时间内,只有一个线程访问被保护数据或者代码
jvm的同步是基于进入和退出的时候,使用管程对象实现的
用户线程和守护线程
用户线程:自定义线程,如果用户线程还存活,jvm就不会关闭
public static void main(String[] args){ Thread aa = new Thread(() -> { System.out.println(Thread.currentThread().getName() + "::" + Thread.currentThread().isDaemon()); while(true){ } }, "aa"); aa.start(); }
可以看到下图中一直在死循环,没有return 0;
守护线程:比如垃圾回收,如果没有用户线程在执行了,即使守护线程还在,jvm也会结束
public static void main(String[] args){ Thread aa = new Thread(() -> { System.out.println(Thread.currentThread().getName() + "::" + Thread.currentThread().isDaemon()); while(true){ } }, "aa"); aa.setDaemon(true); //改为守护线程 aa.start(); }
可以看到,即使守护线程运行还没结束,主程序已经return
Synchronized
修饰的对象有以下几种
1)修饰一个代码块,被修饰的代码块称为同步代码快
2)修饰一个方法,被修饰的方法称为同步方法
3)修饰一个静态的方法,作用的范围是整个静态方法,作用的对象是这个类的所有对象
4)修饰一个类,作用的范围是synchronized后面括号括起来的部分,作用的对象是这个类的所有对象
一个关于Synchronized的一个买票小例子
class Ticket{ private int number=30; public synchronized void sale(){ if(number>0){ System.out.println(Thread.currentThread().getName()+"卖出"+(number--)+"剩下"+number); } } } public class Sale { public static void main(String[] args) { Ticket ticket = new Ticket(); new Thread(new Runnable() { @Override public void run() { for(int i=0;i<40;i++){ ticket.sale(); } } },"AA").start(); new Thread(new Runnable() { @Override public void run() { for(int i=0;i<40;i++){ ticket.sale(); } } },"BB").start(); new Thread(new Runnable() { @Override public void run() { for(int i=0;i<40;i++){ ticket.sale(); } } },"CC").start(); } }
Lock
除了synchronized锁,在JDK 1.5,Java提供了更强大的线程同步机制,比起 synchronized 隐式的方式,虽然可以看到它锁的代码片段,但看不到更具体的;不同synchronized锁,Lock锁可以看到它的开始和结束。(用法也是如此,手动创建Lock锁,需要手动关闭Lock锁)
Lock是显性的方式来实现同步
Lock与Synchronized的区别
1)Lock不是java语言内置的,synchronized是java的关键字,因此是内置特性,Lock是类,通过这个类可以实现同步访问
2)Lock和Synchronized有一点非常不同,采用synchronized不需要用户手动加锁解锁,当synchronized方法或者synchronized代码块执行完或者发生异常之后,系统会自动的让线程释放对锁的占用,而Lock则必须手动去释放锁,如果没有释放,则会造成死锁现象
3)Lock可以让等待的线程响应中断,而synchronized却不行,使用synchronized时,线程会一直执行下去,不能够响应中断
4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到
5)Lock可以提高多个线程进行读操作的效率
使用lock锁来实现买票问题
class LTicket{ private int number=30; private final ReentrantLock lock = new ReentrantLock(); public void sale(){ try{ lock.lock(); if(number>0){ System.out.println(Thread.currentThread().getName()+"卖出"+(number--)+"剩下"+number); } }finally { lock.unlock(); } } } public class SaleByLock { public static void main(String[] args) { LTicket ticket = new LTicket(); new Thread(new Runnable() { @Override public void run() { for(int i=0;i<40;i++){ ticket.sale(); } } },"AA").start(); new Thread(new Runnable() { @Override public void run() { for(int i=0;i<40;i++){ ticket.sale(); } } },"BB").start(); new Thread(new Runnable() { @Override public void run() { for(int i=0;i<40;i++){ ticket.sale(); } } },"CC").start(); } }