day37 线程

一、线程安全

二、多线程并发的安全问题

当多个线程并发操作同一临界资源 由于线程切换实际不确定 导致操作顺序出现混乱

产生的程序bug 严重时出现系统瘫痪

临界资源 :操作该资源的完整流程同一时间只能被单一线程操作的资源  

 多线程并发会出现的各种问题、

       如图会出现的各种异常问题

        1. 数组长度不够
        2. 数组下标越界
        3. 0元素过多

两个线程可能会同时读取和修改c.array的长度,从而导致数组长度不一致,进而导致越界异常。在第一个线程使用Arrays.copyOf方法增加数组长度时,第二个线程可能会在此同时读取数组长度,然后在第一个线程修改完成之前,第二个线程又对数组进行了操作,从而导致长度不一致,然后就会出现越界异常。

public class Test {
    public static void main(String[] args) throws InterruptedException {
        Coo c = new Coo();

        Thread t1 = new Thread() {
            @Override
            public void run() {
               synchronized (c){
                  // System.out.println("this1:"+this);
                   for (int i = 0; i < 100; i++) {
                       c.array = Arrays.copyOf(c.array, c.array.length + 1);
                       c.array[c.array.length-1] = i;
                   }
               }
            }
        };

        Thread t2 = new Thread() {
            @Override
            public void run() {
               synchronized (c){
                  // System.out.println("this:"+this);
                   for (int i = 100; i < 200; i++) {
                       c.array = Arrays.copyOf(c.array, c.array.length + 1);
                       c.array[c.array.length-1] = i;
                   }
               }
            }
        };

        t1.start();
        t2.start();

        /**
         * 多执行几次,检查程序可能存在的问题,并尝试分析为什么会出现这些情况,以及解决方案
         *
         *  1. 数组长度不够
         *  2. 数组下标越界
         *  3. 0元素过多
         */
        //Thread.sleep(1000); //阻塞1秒钟,等待上面两个线程干完活再输出
        t1.join();
        t2.join();
        System.out.println(c.array.length);
        System.out.println(Arrays.toString(c.array));
    }
}

 

当一个方法使用synchronized修饰 ,这个方法称之为同步方法,多个线程不能同时在方法内部执行

同步异步的区别 总结来说,同步和异步的区别:请求发出后,是否需要等待结果,才能继续执行其他操作

同步代码块使用的时候需要注意的是同步监视器对象的选择(重点)

1:对象可以是引用数据类型的对象

2:必须保证多个线程看到的对象是同一个

3:在方法上使用synchronized ,那么同步监视器对象就是this,不能自行指定,是默认的

 4: 静态方法上若使用synchronized,则该方法一定具有同步效果
 5注意:静态方法上执行的同步监视器对象不能使用this,而是当前类的类对象

 静态方法中使用同步代码块的锁对象应当是当前类的对象,格式:类名.class
 

 * 类对象:
 *  Class类的一个实例,JVM加载一个类的时候就会实例化一个Class的实例并用于保存加载这个类的
 *  相关信息,因此每个被加载的类都是有且仅有一个Class的实例与之对应,静态方法的锁对象就是它
 *  类对象会在后续的反射知识中详细说明

有限的缩小同步范围可以在保证并发安全的前提下保证效率

互斥锁

当使用多个Synchronized锁定多个代码片段 并且指定的所的对象相同时 这些代码片段就是互斥的

多个线程不能同时调用他们

package com.oracle.day37;

public class SynchronizedDemo4 {
    public static void main(String[] args) {


    Doo d = new Doo();

//    Thread t1 = new Thread(() -> d.methodA());
        Thread t1 = new Thread(){
            @Override
            public void run() {
                d.methodA();
                d.methodB();
            }
        };
//    Thread t2 = new Thread(() -> d.methodB());
        Thread t2 = new Thread(){
            @Override
            public void run() {
                d.methodA();
                d.methodB();
            }
        };

    t1.start();
    t2.start();
    }
}
class Doo{
    public synchronized void methodA()  {
        Thread t = Thread.currentThread();
        System.out.println(t.getName()+"正在执行方法A");

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(t.getName()+"方法A执行完毕");
    }
    public static void methodB() {
        Thread t = Thread.currentThread();
        System.out.println(t.getName()+"正在执行方法B");

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(t.getName()+"方法B执行完毕");
    }
}

死锁

在没有释放一把锁的同时调用了另一把锁   

锁中放锁

线程的通讯

每一个线程都是独立运行的状态 但需要多个线程完成同一件事

需要多个线程有规律地运行

线程之间就需要通信,告知对方自己的状态

概念 等待队列 唤醒

相关方法:

 void join()线程进入等待状态 等待另一条线程执行完毕然后继续执行

void wait()释放锁标记,进入等待队列

void wait(long time)释放锁 进入等待队列等待多长时间

void notify()唤醒线程

void notifyAll()唤醒全部线程

package com.oracle.day37.thread;

public class ThreadDemo2 {
    public static Object o = new Object();

    public static void main(String[] args) {
        Thread t1 = new Thread(){
            @Override
            public void run() {
               synchronized(o){
                   for (int i = 1; i <= 26; i++) {
                       System.out.println(i);
                       try {
                           o.wait();
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                       o.notify();
                   }
               }
            }
        };

        Thread t2 = new Thread(){
            @Override
            public void run() {
               synchronized (o){
                   for (int i = 'A'; i <= 'Z'; i++) {
                       System.out.println((char)i);
                       o.notify();
                       try {
                           o.wait();
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }
               }
            }
        };
        t1.start();
        t2.start();
    }
}

锁的几种形式 

①:方法中添加synchronized修饰符

②:使用同步代码块

        synchronized(){};

* synchronized()可以添加
* this
* Object o
* Shop.class
* "abc"

③:Lock接口

要使用Lock接口,必须在线程中创建并获得Lock对象,然后在需要进行线程同步的代码块中使用lock()方法获取锁,使用unlock()方法释放锁。在多线程环境下,每个线程都必须单独创建自己的Lock对象,并进行锁定和解锁。这种方式可以保证每个线程都能够获取到自己的锁,从而在并发访问时保证线程安全性。

class BuyTicketMethod extends Thread{
    private static Integer M = 20;
    private final Lock lock = new ReentrantLock();
    @Override
    public  void run() {
        for (int i = 0; i < 10; i++) {
            lock.lock();
            try {
                if (M > 0){
                    System.out.println("您在"+Thread.currentThread().getName()+"购买成功剩余票是"+(--M)+"张");
                }
            } finally {
                lock.unlock();

            }

        }

    }
}

线程状态(线程的生命周期)

1创建状态:new Thread()对象

2就绪状态:线程对象.start(),线程等待cpu随机分配时间片长度

3运行状态:cpu随机分配给线程执行的cpu时间片

4阻塞状态:暂时让出cpu资源

5死亡状态

文章来源地址https://uudwc.com/A/Gdar3

原文地址:https://blog.csdn.net/weixin_45939821/article/details/132799856

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

h
上一篇 2023年09月12日 04:43
下一篇 2023年09月12日 04:43