如果出现了同步嵌套,就会很容易产生死锁问题.是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象.简单来说死锁是 两个或者两个以上的线程,在抢占CPU的执行权的时候,都处于等待状态.
- public class MyThread extends Thread {
- private boolean flag;
- public MyThread(boolean flag) {
- this.flag = flag;
- }
-
- @Override
- public void run() {
- if (flag) {
- synchronized (LockUtils.objA) {
- System.out.println("true线程进来了持有ObjA锁");
- synchronized (LockUtils.objB) {
- System.out.println("true线程进来了持有ObjB锁");
- }
- }
- } else {
- synchronized (LockUtils.objB) {
- System.out.println("false线程进来了持有ObjB锁");
- synchronized (LockUtils.objA) {
- System.out.println("false线程进来了持有ObjA锁");
- }
- }
- }
- }
- }
-
-
- public interface LockUtils {
- //定义了两把锁对象
- Object objA = new Object();
- Object objB = new Object();
- }
-
-
- public class MyTest {
- public static void main(String[] args) throws InterruptedException {
- //创建了两个线程
- MyThread th1 = new MyThread(true);
- MyThread th2 = new MyThread(false);
- //开启线程
- th1.start();
- th2.start();
- }
- }
运行结果便是如此!你等我,我等你.害!孽缘啊!所以一定要注意切勿造成如此"孽缘"!!!!![]()

为了避免死锁,就出现了一个机制:线程间的等待唤醒机制
这个机制就相当于,生产线程生产出了资源. 也就是有资源了,于是就等着,那不可能一直干等着吧,不通知消费线程,他又怎么知道生产出来了资源!通知后,消费线程便拿到资源,然后消费资源,直到资源没有了,就等着,也不可能干等着吖,得通知生产线程这里没有资源了,需要生产线程去生产.这个 生产线程与消费线程之间的等待与通知对方就比较形象的展示了等待唤醒机制!
生产线程生产出了资源,就会等待消费线程来使用,如果没有通知消费线程,那么消费线程也就会一直等待,因为消费线程并不知道已经有资源了!这样的相互等待就会形成死锁现象!
注意: notify()需要在同步方法或同步块中调用,即在调用前,线程必须获得该对象的对象级别锁. 在调用wait()方法之前,线程必须获得该对象的对象级别锁.
- //共享资源
- public class Buns {
- public String name;
- public int price;
- //定义一个标记
- public boolean flag = false; //false 表示没有资源,true表示有资源
- }
-
-
-
-
- //消费者线程
- public class GetThread extends Thread {
- private Buns buns;
- public GetThread(Buns buns) {
- this.buns = buns;
- }
-
- @Override
- public void run() {
- while (true) {
- synchronized (buns) {
- if (!buns.flag) {
- //如果进来了,说明没有资源,没有资源便会等待
- try {
- buns.wait();
- //线程一旦等待,就会释放锁,下次被唤醒,就从这里醒来,也就是从哪里等待,从哪里醒来
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- //没有进入if语句,就会消费资源
- System.out.println(buns.name + "====" + buns.price);
- //消费资源后,通知生产线程去生产
- buns.flag = false;
- buns.notify();
- }
-
- }
- }
- }
-
-
-
-
- //生产者线程
- public class SetThread extends Thread {
- private Buns buns;
- int i = 0;
- public SetThread(Buns buns) {
- this.buns = buns;
- }
-
- @Override
- public void run() {
- while (true) {
- synchronized (buns) {
- //生产线程,生产出了资源,通知消费线程,消费资源
- if (buns.flag) {
- //进来了,表示有资源
- try {
- //有资源便会开始等待
- buns.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- //生产了资源
- if (i % 2 == 0) {
- buns.name = "肉包子";
- buns.price = 3;
- } else {
- buns.name = "素包子";
- buns.price = 2;
- }
-
- //通知消费者线程
- buns.flag = true; //修改标记
- buns.notify(); //唤醒等待的线程
- }
- i++;
- }
- }
- }
-
-
-
-
- //测试
- public class MyTest {
- public static void main(String[] args) {
- //生成者线程 SetThread
- //消费者线程 GetThread
- //资源 Bun 两个线程共享
- Buns buns = new Buns();
- SetThread th1 = new SetThread(buns);
- GetThread th2 = new GetThread(buns);
- th2.start();
- th1.start();
- }
- }
咱们直接开门见山了, volatile可以解决内存可见性问题. volatile 关键字:当多个线程进行操作共享数据时,可以保证内存中的数据可见。相较于 synchronized 是一种较为轻量级的同步策略。
想要理解volatile为什么能确保可见性,就要先理解Java中的内存模型是什么样的.关于java内存模型,在小编的这篇文章里有浅浅的介绍.
对于可见性,Java提供了 volatile关键字来保证可见性。当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。而普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定的,当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性。另外,通过 synchronized也能够保证可见性, synchronized能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。因此可以保证可见性。
volatile 变量,用来确保将变量的更新操作通知到其他线程。可以将 volatile 看做一个轻量级的锁,但是又与锁有些不同!对于多线程, 不是一种互斥关系. 并且 不能保证变量状态的“原子性操作”!
定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行。在Java中,可以 通过Timer和TimerTask类来实现 定义调度的功能。
- public class MyTest {
- public static void main(String[] args) {
- //定时器 Timer
- Timer timer = new Timer();
-
- MyTimerTask myTimerTask = new MyTimerTask(timer);
- //定时器,2秒后只执行一次该任务。
- timer.schedule(myTimerTask, 2000);
-
- //定时器,重复执行任务。第一次等待2秒执行 ,以后每隔1秒重复执行。
- timer.schedule(myTimerTask, 2000, 1000);
-
- }
- }
-
- //定时任务
- class MyTimerTask extends TimerTask {
- private Timer timer;
- public MyTimerTask(Timer timer) {
- this.timer = timer;
- }
-
- @Override
- public void run() {
- System.out.println("砰~~~~爆炸了");
- timer.cancel(); //取消定时器
- }
- }
(小编也在努力学习更多哟!以后再慢慢分享的啦!)
希望对友友们有所帮助!!!!






