Java多线程总结

概论

多线程是指多个任务同时执行,的目的是为了提高机器性能。实际上在单个cpu时,多线程只是看起来同时进行,在实际上某一时刻它只有一个程序在走。多核cpu同一时刻可以运行多个任务。多线程开发的目标是高可用,高性能,高并发。一个程序可以有多个进程,一个进程可以包含多个线程。


 

1、开启多线程

开启多线程有三个办法,Java多线程的几种创建方式

    1、继承Thread类重写run()方法,调用start()开启。

    2、实现Runnable接口,重写run()方法,借用装饰类Thread调用start()方法:new Thread(new Runnable实现类()).start()。

    3、实现Callabler接口,重写call方法,通过ExecutorService类创建服务,调用其submit方法开启线程,通过其shutdown方法关闭服务。

 

方法三中的call方法可以抛出异常,可以有返回值,方法一二中的run不可抛出异常,没有返回值。多用实现,少用继承(Java中只有接口可以多继承)。

Runnable方便共享资源(并发):

public class Test{
    public static void main(String[] args) {
        Test01 ts = new Test01();
        new Thread(ts,"线程1").start();
        new Thread(ts,"线程2").start();
    }
}
class Test01 implements Runnable{
    //多个线程共享同一个资源
    private int money=9;
    @Override
    public void run() {
        while (true) {
            if (money <= 0) {
                break;
            }else{
                System.out.println(Thread.currentThread().getName()+"-->"+money--);
            }
        }
    }
}

运行结果:


 

2、线程状态

如图所示:

1、进入就绪的方式:调用start()方法、接触阻塞、调用yield()方法、JVM内部控制

2、进入阻塞的方式:调用sleep()方法、调用wait()方法、调用join()方法、IO读写操作

3、不建议使用stop()或者destroy()方法结束线程,推荐让线程体自行执行结束,一般使用加入标识的方式控制线程,避免进入死循环。

 

使用getState()可以获取线程的状态:

public static enum State {
        NEW,
        RUNNABLE,
        BLOCKED,
        WAITING,
        TIMED_WAITING,
        TERMINATED;
        private State() {
        }
    }

3、Thread类常用方法

构造器:

     new  Thread(子类对象)            不设置Name,默认为thread-x ,x为线程个数。

     new  Thread(子类对象,线程Name)       设置线程Name

常用静态方法:

     Thread.sleep(毫秒)              使得线程阻塞。常常用于模拟延迟。

     Thread.currentThread()              获取此处在运行的线程对象。常常配合其它方法使用。

     Thread.yield()                此线程主动释放cpu,进入就绪状态。

常用普通方法:

     setName(名字)               设置线程名字。

     getName()                   获取线程名字。

     isAlive()                    返回线程是否活着。

     jion()                   插队,在其它线程中使用让其它线程阻塞,等它先执行完。

     setDaemon(boolean  b)          设置是否为守护线程。线程开启时默认为用户线程。只要所有的用户线程执行完毕,程序就结束。

     setPriority(优先级)             设置优先级,1-10。提供常量:Thread.MAX_PRIORITY、Thread.MIN_PRIORITY、Thread.NORM_PRIORITY。

     getPriority()                  获取优先级。并不是优先级大的就一定先执行,它只是给虚拟机的建议。

     getState()                  获取线程状态。


4、并发控制

为了保证多个线程操作同一个对象时不产生数据错误,需要对并发进行控制。

4.1 synchronized 锁

我们可以使用 synchronized 同步方法或同步块对指定的对象的资源进行锁定,本线程锁了它,其它线程就得排队等本线程用完(释放锁)才能用这个对象。synchronized是可重入锁,Java可重入锁学习

synchronized 方法:

    在方法前面加上synchronized声明,此方法便为同步方法,它锁的是this对象。它锁不到其它类的对象(非this)。

    synchronized void test() {
      
    }

synchronized块:

    可以锁任何对象。精准定位。

    void test() {
        synchronized(Object ob) {
        
        }
    }

4.2 volatile 声明变量

1、对volatile变量的写会立即刷新到主存
2、对volatile变量的读会读主存中的新值

4.3 死锁

简介:

    过多的同步可能造成互相不释放资源,从而导致互相等待,一般发生与同步中持有多个对象的锁。

例如:

    一个不可重入锁多次获取同一个对象的锁,就会产生死锁。

如何避免:
    不在同一个代码块中,同时拥有多个对象的锁。


 

5、线程通信

线程之间可以进行协作,实现线程之间的通信借助java.lang.Object类中的方法:

final void wait();    //线程释放拥有的锁,进入等待
final void wait(long time);    //线程进入等待,在指定毫秒数之后进入就绪状态
final void notifiy();    //唤醒一个处于等待状态的线程
final void notifyAll();    //唤醒同一个对象上所有调用wait()方法的线程

注意:这些方法只能使用在同步代码块中。例子:Java消费者生产者模式,并发控制。

 

posted @ 2022-12-04 20:27  在博客做笔记的路人甲  阅读(74)  评论(0编辑  收藏  举报