关于JAVA中的多线程问题

1、什么是进程?什么是线程?

进程(Process):进程是指在计算机中运行的一个程序。

线程(Thread):线程是进程内的执行单元,也被称为轻量级进程。一个进程可以包含很多个线程,线程是并发执行的,多个线程可以同时执行不同的任务。

2、JAVA中如何实现多线程?

(1)第一种方式:继承Thread类,重写Run方法

①创建一个类来继承Thread类

//第一种方式:继承Thread类
// ①先继承Thread类
public class MyThread extends Thread {
    public MyThread(String name){
        super(name);
    }
    //②重写run方法
    @Override
    public void run() {
        for(int i=0;i<20;i++){
            System.out.println(getName()+"================="+i);
        }
    }
}

②创建一个测试类

public class Test {
    public static void main(String[] args){
        //创建一个线程对象
        MyThread t1=new MyThread("线程A");
        //开启线程:
        t1.start();
        for (int i = 0; i <20 ; i++) {
            System.out.println("主线程=============="+i);
        }
    }
}

运行结果(部分):

线程A=================0
线程A=================1
线程A=================2
线程A=================3
线程A=================4
主线程==============0
线程A=================5
线程A=================6
主线程==============1
线程A=================7
主线程==============2
线程A=================8
主线程==============3
主线程==============4
主线程==============5
主线程==============6
主线程==============7
线程A=================9
主线程==============8
线程A=================10
主线程==============9
线程A=================11
主线程==============10

这个结果说明了, 程序启动之后运行main时候,java虚拟机启动一个进程,主线程在main()调用时候被创建。随着调用Thread对象的start方法,又一个线程启动,整个应用就在多线程下运行了。

(2)实现Runnable接口,重写Run方法

①通过实现Runnable接口来创建线程类

//通过实现Runnable接口来创建线程任务类
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for(int i=0;i<20;i++){
        //Thread.currentThread().getName()获取运行时的线程名
            System.out.println(Thread.currentThread().getName()+"========================="+i);
        }
    }
}

②创建一个测试类 

public class Test {
    public static void main(String[] args) {
        //创建线程任务类对象
        MyRunnable my=new MyRunnable();
        //创建线程对象.Runnable
        Thread t1=new Thread(my,"线程A");
        //开启线程
        t1.start();
        for (int i = 0; i <20 ; i++) {
            System.out.println("主线程=============="+i);
        }

    }
}

运行结果:

主线程==============0
主线程==============1
线程A=========================0
主线程==============2
线程A=========================1
主线程==============3
主线程==============4
主线程==============5
主线程==============6
主线程==============7
主线程==============8
主线程==============9
主线程==============10

对于这两种方法,在使用时推荐使用第二种方式,因为继承只能够单继承,在开发中的扩展性比较差,接口的话可以多实现,扩展性较第一种方式强。

3、Thread类中常用的方法

①start():启动线程,使线程进入可执行状态并开始执行run()方法中的代码。

②run():定义线程的执行逻辑,需要在子类中重写该方法。线程启动后会自动调用run()方法来执行线程的任务。

③sleep(long millis):使当前线程休眠指定的时间(以毫秒为单位)。调用该方法会暂停线程的执行,让出CPU资源给其他线程。

④join():让一个线程等待另一个线程完成后再继续执行。调用该方法会阻塞当前线程,直到目标线程执行完成。

⑤interrupt():中断线程,给线程发送中断信号。该方法会设置线程的中断状态,并在线程中对应的位置抛出InterruptedException异常。

⑥isInterrupted():检查线程是否被中断。该方法返回一个boolean值,表示线程的中断状态。

⑦getId():获取线程的唯一标识符(ID)。每个线程都有一个独一无二的ID,用于区分不同的线程。

⑧getName():获取线程的名称。线程可以通过构造方法或setName()方法设置名称。

4、线程安全问题

线程存在线程安全问题,线程安全问题是由于多个线程访问共享资源而产生的问题。

解决线程安全问题的办法:

使用锁,

5、线程的死锁问题

(1)什么是死锁?

当第一个线程拥有A对象锁标记,并等待B对象锁标记,同时第二个线程拥有B对象锁标记,并等待A对象锁标记时,产生死锁。

死锁发生时需要满足的四个条件:

①互斥条件:资源一次只能被一个线程占用

②请求与保持条件:线程在持有资源的同时又请求其他线程所持有的资源

③不可剥夺条件:已经分配的资源不能被其他线程强制性地抢占

④循环等待条件:多个线程之间形成一种循环等待资源的关系

(2)死锁的案例

两个人一个男孩有画笔,一个女孩有画板,但是互相都不愿意给对方东西让对方画画。

public class LockObject {

    //一个锁的类
    //画笔对象
    public static Object brush=new Object();
    //画板对象
    public static Object drawingBoard=new Object();

}

//创建一个男孩类
public class BoyRunnable implements Runnable{
    @Override
    public void run() {
        synchronized (LockObject.brush){
            System.out.println("男孩获取到一只画笔");
            synchronized (LockObject.drawingBoard){
                System.out.println("男孩获得一个画板");
                System.out.println("男孩可以进行画画了");
            }
        }
    }
}
//创建一个女孩类
public class GirlRunnable implements Runnable {
    @Override
    public void run() {
        synchronized (LockObject.drawingBoard){
            System.out.println("女孩获得了一个画板");
            synchronized (LockObject.brush){
                System.out.println("女孩获得了一只画笔");
                System.out.println("女孩开始画画了");
            }
        }
    }
}
//Test测试类
public class Test {
    public static void main(String[] args) {
        //创建男孩对象
        BoyRunnable boy=new BoyRunnable();
        Thread t1=new Thread(boy);
        //创建女孩对象
        GirlRunnable girl=new GirlRunnable();
        Thread t2=new Thread(girl);
        //开启线程
        t1.start();
        t2.start();
    }
}

运行结果:

女孩获得了一个画板
男孩获取到一只画笔

(3)如何解决死锁问题

①尽量避免出现锁的嵌套

②设置超时时间:在获取锁资源时设置超时时间,如果在指定时间内无法获得所需的锁资源,则放弃当前的锁请求,释放已经持有的锁,并进行适当的处理,避免死锁的持续发生

③及时释放锁资源:在使用完锁资源后及时释放,避免长时间持有锁,减少死锁的可能性


6、线程通信

wait和sleep的区别:

①wait需要使用notify或者notifyAll唤醒,而sleep到时候自动唤醒

②wait来自于Object类中,sleep来自Thread类中

③wait会释放锁资源,sleep不会释放锁资源

④wait必须放在同步代码中,而sleep可以放在任意位置

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值