外观
线程冲突
线程冲突
1.产生原因
1.多个线程同时操作同一个资源
2.多个线程操作频度和操作时间很相近
2.解决方法
1.线程隔离
不共享资源
1.1栈隔离(使用局部变量)
1.2给每个线程一个资源副本,ThreadLocal
2.通过同步机制
2.1 synchronized
1.同步代码块 synchronized修饰代码块称为同步代码块,参数为需要同步的线程需要用到的对象 synchronized (object) { i++; System.out.println("MyThread2:"+i); }
2.同步体包含所有的同步代码,保证同一范围只能有一个线程在该区域运行
3.同步体线程运行到该区域时会尝试加锁,若没有锁就直接加锁,若已加锁(加锁未成功)则此线程进入阻塞状态直到运行的线程离开同步体,阻塞才能结束
4.JDK1.6之前通过操作系统的核心态锁机制
5.synchronized 用来控制使用同步对象的线程
6.锁对象,阻塞使用对象的线程
7.是一个Java的关键字是同步锁
8.修饰一个代码块,表示该代码块是一个同步块,可以保证同一时间只能有一个使用该对象的线程
9.修饰一个方法,表示该方法是同步方法,其作用范围是整个方法,锁定的是this
10.修饰一个静态方法,锁定的是类名.class
11.不可修饰变量和类
作用
1.对某个对象(信号量)上锁
2.保证线程在互斥区互斥
3.解决了多个线程操作同一资源冲突的问题
线程安全
多个线程同时操作该类的方法,不会产生线程冲突
单例模式饿汉模式线程安全,懒汉模式不安全(可加synchronized )解决
public class SynchronizedTest {
static int i = 1;
static class MyThread1 extends Thread{
// 相当于信号量,用来线程同步
private Object object;
public MyThread1() {
}
MyThread1(Object object){
this.object = object;
}
@Override
// public void run() {
// // 同步代码块
// // synchronized修饰代码块称为同步代码块,参数为需要同步的线程需要用到的对象(锁定的是用到的对象)
// synchronized (object) {
// i++;
// System.out.println("MyThread1:"+i);
// }
// }
// synchronized修饰方法该方法为同步方法,锁定的是this
public synchronized void run() {
// 同步代码块
// synchronized修饰代码块称为同步代码块,参数为需要同步的线程需要用到的对象
i++;
System.out.println("MyThread1:"+i);
}
}
static class MyThread2 extends Thread{
private Object object;
public MyThread2() {
}
MyThread2(Object object){
this.object = object;
}
@Override
// public void run() {
// // 同步代码块
// // synchronized修饰代码块称为同步代码块,参数为需要同步的线程需要用到的对象
// synchronized (object) {
// i++;
// System.out.println("MyThread2:"+i);
// }
// }
public synchronized void run() {
// 同步代码块
// synchronized修饰代码块称为同步代码块,参数为需要同步的线程需要用到的对象
i++;
System.out.println("MyThread2:"+i);
}
}
public static void main(String[] args) {
// testCountNotSyn();
// testCountSyn();
testCountSynWithMethd();
}
private static void testCountNotSyn() {
// 线程不同步
Thread thread1 = new MyThread1();
Thread thread2 = new MyThread2();
thread1.start();
thread2.start();
}
private static void testCountSyn() {
// 线程同步
Object object = new Object();
Thread thread1 = new MyThread1(object);
Thread thread2 = new MyThread2(object);
thread1.start();
thread2.start();
}
private static void testCountSynWithMethd() {
// 线程同步
Object object = new Object();
Thread thread1 = new MyThread1(object);
// Thread thread2 = new MyThread2(object);
Thread thread2 = new Thread(thread1);
thread1.start();
thread2.start();
}
}
2.2锁
1.synchronized 和lock的区别
1.都是线程同步机制
2.synchronized 是关键字,lock是Java对象,实现机制不用,lock更灵活
3.可重入锁:已经加锁可以再次加锁
4.是否异常释放锁:synchronized 异常自动释放,lock需要手动释放
5.操作方式:synchronized 自动加锁,lock手动加锁
6.性能:lock性能高
1.来源: lock是一个接口,而synchronized是java的一个关键字,synchronized是内置的语言实现;
2.异常是否释放锁: synchronized在发生异常时候会自动释放占有的锁,因此不会出现死锁;而lock发生异常时候,不会主动释放占有的锁,必须手动unlock来释放锁,可能引起死锁的发生。(所以最好将同步代码块用try catch包起来,finally中写入unlock,避免死锁的发生。)
3.是否响应中断 lock等待锁过程中可以用interrupt来中断等待,而synchronized只能等待锁的释放,不能响应中断;
4.是否知道获取锁 Lock可以通过trylock来知道有没有获取锁,而synchronized不能;
5.Lock可以提高多个线程进行读操作的效率。(可以通过readwritelock实现读写分离)
6.在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
7.synchronized使用Object对象本身的wait 、notify、notifyAll调度机制,而Lock可以使用Condition进行线程之间的调度。
1.来源: lock是一个接口,而synchronized是java的一个关键字,synchronized是内置的语言实现;
2.异常是否释放锁: synchronized在发生异常时候会自动释放占有的锁,因此不会出现死锁;而lock发生异常时候,不会主动释放占有的锁,必须手动unlock来释放锁,可能引起死锁的发生。(所以最好将同步代码块用try catch包起来,finally中写入unlock,避免死锁的发生。)
3.是否响应中断 lock等待锁过程中可以用interrupt来中断等待,而synchronized只能等待锁的释放,不能响应中断;
4.是否知道获取锁 Lock可以通过trylock来知道有没有获取锁,而synchronized不能;
5.Lock可以提高多个线程进行读操作的效率。(可以通过readwritelock实现读写分离)
6.在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
7.synchronized使用Object对象本身的wait 、notify、notifyAll调度机制,而Lock可以使用Condition进行线程之间的调度。
public class LockTest {
static int i =0;
static class Thread1 implements Runnable{
@Override
public void run() {
Lock lock = new ReentrantLock();
// if (!lock.tryLock()) {
// System.out.println("Thread1等待");
// }
// 对当前线程加锁
lock.lock();
// i++;
System.out.println("Thread1: "+i);
i++;
// 对当前线程解锁
lock.unlock();
}
}
static class Thread2 implements Runnable{
@Override
public void run() {
Lock lock = new ReentrantLock();
// if (!lock.tryLock()) {
// System.out.println("Thread2等待");
// }
lock.lock();
i++;
System.out.println("Thread2: "+i);
lock.unlock();
}
}
public static void main(String[] args) {
test();
}
private static void test() {
Thread thread1 = new Thread(new Thread1());
Thread thread2 = new Thread(new Thread2());
thread1.start();
thread2.start();
}
}
死锁
1.产生原因
1.多个线程共同操作了的资源
2.线程可以单独锁定部分资源且不释放
2.解决死锁
1.线程隔离
2.不允许锁定部分资源
3.要有释放条件
public class DiedLock {
static class Thread1 implements Runnable{
// 定义资源
private Object a;
private Object b;
public Thread1(Object a, Object b) {
this.a = a;
this.b = b;
}
@Override
public void run() {
synchronized (a) {
System.out.println("Thread1锁a");
synchronized (b) {
System.out.println("Thread1锁b");
}
}
}
}
static class Thread2 implements Runnable{
// 定义资源
private Object a;
private Object b;
public Thread2(Object a, Object b) {
this.a = a;
this.b = b;
}
@Override
public void run() {
synchronized (b) {
System.out.println("Thread2锁b");
synchronized (a) {
System.out.println("Thread2锁a");
}
}
}
}
public static void main(String[] args) {
diedLock();
}
private static void diedLock() {
Object a = new Object();
Object b = new Object();
Thread thread1 = new Thread(new Thread1(a, b));
Thread thread2 = new Thread(new Thread2(a, b));
thread1.start();
thread2.start();
}
}
活锁
1.原因
1.共享资源
2.多个线程单独锁定部分资源
3.周期性释放资源
2.解决
不允许周期性释放资源,必须随机释放
2.3.notify()与wait()
notify()唤醒信号(随机唤醒对象监视器(阻塞的线程)中的任意一个)
nitifyAll()唤醒所有阻塞的线程到就绪队列
wait()阻塞使用它的线程
public class WaitNotifyTest {
static class Thread1 implements Runnable{
// 信号量
private Object mutux;
public Thread1(Object mutux) {
this.mutux = mutux;
}
@Override
public void run() {
synchronized (mutux) {
String[] strings = "a,b,c".split(",");
for (int i = 0; i < strings.length; i++) {
// 每次运行之前唤醒信号
mutux.notify();
System.out.print(strings[i]+",");
// 每次运行之后阻塞信号
try {
mutux.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 执行完毕唤醒所有线程自然结束
mutux.notify();
}
}
}
static class Thread2 implements Runnable{
private Object mutux;
public Thread2(Object mutux) {
this.mutux = mutux;
}
@Override
public void run() {
synchronized (mutux) {
String[] strings = "1,2,3".split(",");
for (int i = 0; i < strings.length; i++) {
mutux.notify();
System.out.print(strings[i]+",");
try {
mutux.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) {
print();
}
private static void print() {
Object mutex = new Object();
Thread thread1 = new Thread(new Thread1(mutex));
Thread thread2 = new Thread(new Thread2(mutex));
thread1.start();
thread2.start();
}
}
2.4slee()与wait()的区别
1.都可以让线程进入阻塞
2.来自不同的类,sleep->Thread,wait->Object
3.sleep没有释放锁,wait释放了锁
4.sleep是让自己挂起,而wait是让使用它的线程挂起