前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java并发编程(三)

java并发编程(三)

作者头像
疯狂的KK
发布2020-02-26 09:35:58
2750
发布2020-02-26 09:35:58
举报
文章被收录于专栏:Java项目实战Java项目实战

继续根据大纲整理、

16:Synchronized代码块和锁失效

无论Synchronized锁的是方法还是代码块,本质上还是锁的当前对象。

代码语言:javascript
复制
package io.renren.controller;
/**
 * @author zhaokkstart
 * @create 2020-02-24 9:42
 */
public class TestSynchronizedObject {
    public static void main(String[] args) {
        final MyObject myObject_first = new MyObject();
        final MyObject myObject_seconde = new MyObject();
        new Thread(()->{
            myObject_first.print("线程A");

        },"A").start();

        new Thread(()->{

            myObject_seconde.print("线程B");
        },"B").start();

    }

}

class MyObject {
    public void print(String str) {
        System.out.println("线程" + Thread.currentThread().getName() + "开始执行");
        synchronized (String.class) {
            for (int i = 0; i <= 10; i++) {
                System.out.println(str + " ." + i + ". ");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
            }
        }
        System.out.println("线程" + Thread.currentThread().getName() + "执行结束");
    }
}

运行结果:

代码语言:javascript
复制
线程A开始执行
线程A .0. 
线程B开始执行
线程A .1. 
线程A .2. 
线程A .3. 
线程A .4. 
线程A .5. 
线程A .6. 
线程A .7. 
线程A .8. 
线程A .9. 
线程A .10. 
线程B .0. 
线程A执行结束
线程B .1. 
线程B .2. 
线程B .3. 
线程B .4. 
线程B .5. 
线程B .6. 
线程B .7. 
线程B .8. 
线程B .9. 
线程B .10. 
线程B执行结束

为什么我锁了String的所有实例化对象,对Myobject没有加锁,他仍会互斥执行呢?

因为 sychoronized 是使用括号里的对象来上锁,而 String.class 不是String 类的全部实例,而是一个对象,是一个类型为 Class 的对象,因此,如果你使用不同的这样的 class 对象来同步,则获得的是不同的锁。

代码语言:javascript
复制
   synchronized (str) {
            for (int i = 0; i <= 10; i++) {
                System.out.println(str + " ." + i + ". ");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
            }
        }
代码语言:javascript
复制
线程A开始执行
线程A .0. 
线程B开始执行
线程B .0. 
线程A .1. 
线程B .1. 
线程A .2. 
线程B .2. 
线程A .3. 
线程B .3. 
线程A .4. 
线程B .4. 
线程B .5. 
线程A .5. 
线程A .6. 
线程B .6. 
线程B .7. 
线程A .7. 
线程B .8. 
线程A .8. 
线程A .9. 
线程B .9. 
线程A .10. 
线程B .10. 
线程A执行结束
线程B执行结束

如果的想锁住这段代码,只需要锁住同一个对象即可

代码语言:javascript
复制
 synchronized (TestSynchronizedObject.class) {
            for (int i = 0; i <= 10; i++) {
                System.out.println(str + " ." + i + ". ");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
            }
        }
代码语言:javascript
复制
线程A开始执行
线程A .0. 
线程B开始执行
线程A .1. 
线程A .2. 
线程A .3. 
线程A .4. 
线程A .5. 
线程A .6. 
线程A .7. 
线程A .8. 
线程A .9. 
线程A .10. 
线程A执行结束
线程B .0. 
线程B .1. 
线程B .2. 
线程B .3. 
线程B .4. 
线程B .5. 
线程B .6. 
线程B .7. 
线程B .8. 
线程B .9. 
线程B .10. 
线程B执行结束

17:线程间通信

多个线程实现顺序打印,synchronized对应wait().notifiy().notifyAll(),搭配使用,如果wait不与之配合使用会报非法监控异常,从而解释了synchronized锁的是对象,所以将其设计为Object方法,利用lock实现,对应await(),sigbal(),那么countDownLatch等肯定也能实现

代码语言:javascript
复制
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


class ShareResource {
    private int number = 1;//1:A 2:B 3:C

    private Lock lock = new ReentrantLock();
    private Condition cd1 = lock.newCondition();
    private Condition cd2 = lock.newCondition();
    private Condition cd3 = lock.newCondition();

    public void print5(int totalLoopNumber) {
        lock.lock();
        try {
            //判断
            while (number != 1) {
                cd1.await();
            }
            //干活
            for (int i = 1; i <= 5; i++) {
                System.out.println(Thread.currentThread().getName() + "\t totalLoopNumber="
                        + totalLoopNumber + "\t i=" + i);

            }
            //通知
            number = 2;
            cd2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }


    public void print10(int totalLoopNumber) {
        lock.lock();
        try {
            //判断
            while (number != 2) {
                cd2.await();
            }
            //干活
            for (int i = 1; i <= 10; i++) {
                System.out.println(Thread.currentThread().getName() + "\t totalLoopNumber="
                        + totalLoopNumber + "\t i=" + i);
            }
            //通知
            number = 3;
            cd3.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public void print15(int totalLoopNumber) {
        lock.lock();
        try {
            //判断
            while (number != 3) {
                cd3.await();
            }
            //干活
            for (int i = 1; i <= 15; i++) {
                System.out.println(Thread.currentThread().getName() + "\t totalLoopNumber="
                        + totalLoopNumber + "\t i=" + i);

            }
            //通知
            number = 1;
            cd1.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
}


/**
 * @author xialei
 * @Description: 多线程之间按顺序调用,实现A->B->C
 * 三个线程启动,要求如下:
 * <p>
 * AA打印5次,BB打印10次,CC打印15次
 * 接着
 * AA打印5次,BB打印10次,CC打印15次
 * ......来10轮
 */
public class ThreadOrderAccess {
    public static void main(String[] args) {
        ShareResource shareResource = new ShareResource();
        new Thread(() -> {

            for (int i = 1; i <= 10; i++) {
                shareResource.print5(i);
            }
        }, "AA").start();

        new Thread(() -> {

            for (int i = 1; i <= 10; i++) {
                shareResource.print10(i);
            }
        }, "BB").start();

        new Thread(() -> {

            for (int i = 1; i <= 10; i++) {
                shareResource.print15(i);
            }
        }, "CC").start();

    }
}

18:阻塞式线程安全队列

阻塞:在某些情况下挂起线程,一旦条件满足,被挂起的线程自动唤醒。

ArrayBlockingQueue:ー个由数组结构组成的有界阻塞队列

LinkedBlockingqueue:一个由链表结构组成的有界阻塞队列

Synchronousqueue:一个不存储元素的阻塞队列

当阻塞队列满时,再往队列add元素会异常

当队列空时,再从队列remove元素会异常

代码语言:javascript
复制
public class BlockingQueueDemo {

    public static void main(String[] args) {

        BlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);

        blockingQueue.add("1");
        blockingQueue.add("2");
        blockingQueue.add("3");
        blockingQueue.add("4");

    }

}
Exception in thread "main" java.lang.IllegalStateException: Queue full
  at java.util.AbstractQueue.add(AbstractQueue.java:98)
  at java.util.concurrent.ArrayBlockingQueue.add(ArrayBlockingQueue.java:312)
  at com.atkk.thread.BlockingQueueDemo.main(BlockingQueueDemo.java:20)
 blockingQueue.add("1");
        blockingQueue.add("2");
        blockingQueue.add("3");
       // blockingQueue.add("4");
        blockingQueue.remove();
        blockingQueue.remove();
        blockingQueue.remove();
        blockingQueue.remove();
   Exception in thread "main" java.util.NoSuchElementException
  at java.util.AbstractQueue.remove(AbstractQueue.java:117)
  at com.atkk.thread.BlockingQueueDemo.main(BlockingQueueDemo.java:24)     

Synchronousqueue为不存储元素,即单个元素队列

代码语言:javascript
复制
package com.kk.thread;

import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;

/**
 * @author zhaokkstart
 * @create 2020-02-24 13:25
 */
public class BlockingQueueDemo {

    public static void main(String[] args) {

        BlockingQueue<Object> blockingQueue = new SynchronousQueue<>();
        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + "\t put 1");
                blockingQueue.put("1");
                System.out.println(Thread.currentThread().getName() + "\t put 2");
                blockingQueue.put("2");
                System.out.println(Thread.currentThread().getName() + "\t put 3");
                blockingQueue.put("3");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();
        new Thread(() -> {
            try {
                Thread.sleep(5000);
                System.out.println(Thread.currentThread().getName()+blockingQueue.take()+"\t get");
                Thread.sleep(5000);
                System.out.println(Thread.currentThread().getName()+blockingQueue.take()+"\t get");
                Thread.sleep(5000);
                System.out.println(Thread.currentThread().getName()+blockingQueue.take()+"\t get");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "B").start();

    }
}

19:守护线程和用户线程

守护线程:服务其他的线程

用户线程:程序自定义的线程

那么当主线程退出时,守候子线程会执行完毕吗?不一定执行

代码语言:javascript
复制
package com.kk.thread;

/**
 * @author zhaokkstart
 * @create 2020-02-24 13:55
 */
public class ThreadException {
    public static void main(String[] args) throws InterruptedException {
        Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
            System.out.printf("线程遇到异常。。。"+thread.getName()+"\n \t", thread.getName(), throwable.getMessage());
        });
        Thread a = new Thread(() -> {
            System.out.printf("线程[name: %s,A:%s]Hello world \n ",);
        }, "A");
        a.setDaemon(true);
        a.start();
    }
}

守候线程执行依赖于执行时间

20:线程上下文切换

多线程环境中,

当一个线程的状态由Runnable转换为非Runnable(Blocked、Waiting、Timed_Waiting)时,相应线程的上下文信息(包括cpu的寄存器和程序计数器在某一时间点的内容等)需要被保存,以便相应线程稍后再次进入Runnable状态时能够在之前的执行进度的基础上继续前进。而一个线程从非Runnable状态进入Runnable状态可能涉及恢复之前保存的上下文信息。这个对线程的上下文进行保存和恢复的过程就被称为上下文切换。

原文链接:

https://blog.csdn.net/u014527912/article/details/78939781

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-02-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 赵KK日常技术记录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ArrayBlockingQueue:ー个由数组结构组成的有界阻塞队列
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档