多线程并发和锁机制 (0119)

本文详细介绍了Java中MyThread继承Thread的方式,创建线程的三种方法(extendsThread、implementsRunnable和Callable),讨论了线程安全、同步代码块、同步方法和Lock的使用,以及线程池的概念和死锁问题的解决策略。
摘要由CSDN通过智能技术生成

一.MyThread继承Thread父类

使用父类方法构造器。MyThread 继承 Thread执行父类Thread(String name)构造器,为当前线程设置名字了

public class MyThread extends Thread{
    public MyThread(String name){
        super(name); //1.执行父类Thread(String name)构造器,为当前线程设置名字了
    }
    @Override
    public void run() {
        //2.currentThread() 哪个线程执行它,它就会得到哪个线程对象。
        Thread t = Thread.currentThread();
        for (int i = 1; i <= 3; i++) {
            //3.getName() 获取线程名称
            System.out.println(t.getName() + "输出:" + i);
        }
    }
}

父类Thread(String name)构造器

1.线程与进程的区别:

二.创建线程的三种方式

1.extends Thread

public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("Value"+i);

        }
    }

    public static void main(String[] args) {
        MyThread t1=new MyThread();
        t1.start();
    }
}

2.实现implements Runnable 接口 

通过implements Runnable接口,使线程的执行逻辑封装在实现了run()方法的类中。以后,创建Thread类实例时,可将实现了Runnable接口的类的实例,即mr,传递给Thread的构造方法。

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("Value"+i);
        }
    }

    public static void main(String[] args) {
        MyRunnable mr=new MyRunnable();
        Thread t1=new Thread(mr);
        t1.start();
    }
}

3.implements Callable 接口

Callable接口实际上是属于Executor框架中的功能类,Callable接口与Runnable接口的功能类似,但提供了比Runnable更加强大的功能。

Callable可以在任务结束的时候提供一个返回值,Runnable无法提供这个功能。

Callable的call方法分可以抛出异常,而Runnable的run方法不能抛出异常。

Thread和Runnable的异同点

Thread 和 Runnable 的相同点:都是“多线程的实现方式”。
Thread 和 Runnable 的不同点
Thread 是类,而Runnable是接口;如果有其他类需要继承的话肯定是用Runnable接口了。Thread本身是实现了Runnable接口的类。我们知道“一个类只能有一个父类,但是却能实现多个接口”,因此Runnable具有更好的扩展性。
此外,Runnable还可以用于“资源的共享”。即,多个线程都是基于某一个Runnable对象建立的,它们会共享Runnable对象上的资源。

Thread、Runnable、Callable三者特点\异同:

Thread:继承类实现,简单地定义一个线程,而不用担心单继承的限制,并且不需要共享数据。

Runnable:推荐。重写run()方法。接口实现,若需要定义线程的同时扩展其他类的功能,可在多个线程之间共享数据。可以定义一个类A实现Runnable接口;然后,通过new Thread(new A())等方式新建线程。

Callable:接口实现,重写call()方法。可以在任务结束的时候提供一个返回值,call方法可以抛出异常。

public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() {
        int sum=0;
        for (int i = 0; i < 10; i++) {
            sum+=i;
        }
        return sum;
    }

    public static void main(String[] args) {
        Callable<Integer>mc=new MyCallable();
        FutureTask<Integer>ft=new FutureTask<>(mc);
        Thread t1=new Thread(ft);
        t1.start();
        try {
            Integer result=ft.get();
            System.out.println("Sum from Callable"+result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

三:线程安全

线程安全问题指的是,多个线程同时操作同一个共享资源的时候,可能会出现业务安全问题。

1.同步代码块

1.建议把共享资源作为锁对象, 不要将随便无关的对象当做锁对象
2.对于实例方法,建议使用this作为锁对象
3.对于静态方法,建议把类的字节码(类名.class)当做锁对象

//锁对象:必须是一个唯一的对象(同一个地址)
synchronized(锁对象){
    //...访问共享数据的代码...
}
// 小明 小红线程同时过来的
public void drawMoney(double money) {
    // 先搞清楚是谁来取钱?
    String name = Thread.currentThread().getName();
    // 1、判断余额是否足够
    // this正好代表共享资源!
    synchronized (this) {
        if(this.money >= money){
            System.out.println(name + "来取钱" + money + "成功!");
            this.money -= money;
            System.out.println(name + "来取钱后,余额剩余:" + this.money);
        }else {
            System.out.println(name + "来取钱:余额不足~");
        }
    }
}


2.同步方法

其实同步方法,就是把整个方法给锁住,一个线程调用这个方法,另一个线程调用的时候就执行不了,只有等上一个线程调用结束,下一个线程调用才能继续执行。

使用synchronized修饰方法,确保在同一时间只有一个线程能够访问该方法。这种方式适用于整个方法需要被同步的情况


    // 同步方法
    public synchronized void increment() {
        count++;
    }


3.Lock锁

1.首先在成员变量位子,需要创建一个Lock接口的实现类对象(这个对象就是锁对象)
	private final Lock lk = new ReentrantLock();
2.在需要上锁的地方加入下面的代码
	 lk.lock(); // 加锁
	 //...中间是被锁住的代码...
	 lk.unlock(); // 解锁

四:线程池的使用

五.死锁

死锁问题:

1: 某一个线程一直持有锁 不解锁 2: 两个线程之间互相持有对方需要的锁 两个线程都持有了一把锁 接着都需要再持有一把锁(也是对方目前持有的锁)才可以 执行任务

解决:

1: 不写死锁(拿到一把锁 不获取另一把锁) 2: 获取一把锁之后 尝试获取第二把锁,失败的话 立马放弃第一把锁,再重新自旋 获取第一把锁

public class TA extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            synchronized (Main.object1){
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("TA - 持有 O1 Lock");
                synchronized (Main.object2){
                    System.out.println("TA - 持有 O2 Lock");
                    Main.num++;
                }
            }
        }
        System.out.println("TA- end");
    }
}
class RA implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            synchronized (Main.object2){
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("RA - 持有 O2 Lock");
                synchronized (Main.object1){
                    System.out.println("RA - 持有 O1 Lock");
                    Main.lock.lock();
                    Main.num++;
                    Main.lock.unlock();
                }
            }
        }
        System.out.println("RA- end");
    }
}

class Main{
    static int num=0;
    static Object object1=new Object();
    static Object object2=new Object();
    static Lock lock=new ReentrantLock();
    public static void main(String[] args) {
        TA ta=new TA();
        RA ra=new RA();
        ta.start();
        Thread t1=new Thread(ra);
        t1.start();
        try {
            ta.join();
            t1.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(num);
    }

}

  • 28
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值