-
线程和进程区别
线程:
1)进程中负责程序执行的执行单元
2)依靠程序执行的顺序控制流,只能使用程序的资源和环境,共享进程的全部资源
3)有自己的堆栈和局部变量,没有单独的地址空间
4)CPU调度和分派的基本单位,持有程序计数器,寄存器,堆栈
进程:
1)系统资源分配和调度的独立单位
2)至少包含一个线程
3)拥有自己的资源
-
线程的创建方式
源码:
1).继承Thread类,实现run方法
//继承Thread类的方法存在单继承的缺陷;
class MyThread extends Thread{
@Override
public void run() {
super.run();
}
}
MyThread myThread=new MyThread();
myThread.start();
2).实现Runnable接口,实现run方法,用实现接口的实例作为Thread类的构造参数创建线程
//Runnable的代码可以被多个线程(Thread实例)共享,适合于多个线程处理统一资源的情况;
class MyRunable implements Runnable{
@Override
public void run() {
}
}
MyRunable myRunable=new MyRunable();
Thread myThread=new Thread(myRunable);
Thread myThread1=new Thread(myRunable);
-
线程交互:互斥与同步
互斥:同一时间只能有一个线程去对临界区进行操作,通过synchronized(intrinsic lock)实现,只有获得lock的线程才能进入synchronized声明的代码块;
同步:线程之间的通信机制;当某些条件不具备时线程处于等待状态,条件满足,需要发出消息来唤醒所有线程;通过 wait()/notify()/notifyAll()实现。
-
死锁产生的四个必要条件(必须同时具备):
- 死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程
1)互斥条件:一个资源每一次只能被一个进程使用
2)请求与保持条件:一个进程因请求资源而阻塞时,对获得的资源保持不放
3)不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
4)循环等待条件:若干进程之间形成一种头尾相接的循环等待关系
避免死锁:
1)合理设置同步区,避免一个线程同时获取多个锁
2)尽量保证一个锁占用一个资源
3)使用tryLock(Timeout)代替内部锁,即加锁顺序,加锁时限
4)对于数据库锁,加解锁必须放在一个数据库连接里
- JAVA互斥锁(synchronized&Lock)
一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该对象的线程将被阻塞。
1)同步方法和非同步方法是否可以同时调用?-->可以
2)一个同步方法可以调用另一个同步方法,一个线程已经拥有某个对象的锁,再次申请时仍然会得到该对象的锁,synchronized获得 的锁是可重入的
3)在继承中,子类重写的同步方法可以调用父类的同步方法
4) synchronized既保证原子性又保证可见性
- CountDownLatch(门闩)
声明一个CountDownLatch对象latch并设定初始值>0,调用latch.countDown()使latch值减一,当latch值变为0,门闩打 开;当不涉及同步,只涉及锁定,用synchronized+wait/notify就显得太重了。这时应该考虑CountDownLatch
await()方法,调用这个方法的线程会被阻塞
countDown()方法,调用这个方法会使计数器减一,当计数器的值为0时,因调用await()方法被阻塞的线程会被唤醒,继续执行。
JAVA高并发的三种实现:https://blog.youkuaiyun.com/java_xth/article/details/81162088