多线程

JAVA(多线程)

创建线程

1.继承Thread类,重写run方法

  Thread不是抽象类,run方法不是抽象方法

  MyThread继承了Thread类之后,他就是一个独立的线程

  要让线程启动,调用start方法

package duoxiancheng;

class MyThread extends Thread{

    @Override
    public void run(){
        System.out.println("线程启动");
    }
}
public class Test1 {

    public static void main(String[] args) {
        MyThread myThread=new MyThread();

        //当调用start方法启动一个线程时,会执行重写的run方法的代码
        myThread.start();//启动线程
    }
}

2.实现Runnable接口

package duoxiancheng;

class MyThread2 implements Runnable{
    @Override
    public void run(){
        System.out.println("实现Runnable");
    }

}
public class Test2 {
    public static void main(String[] args) {
        //想要线程启动,需要调用Thread类中的start
        MyThread2 myThread2=new MyThread2();

        Thread t=new Thread(myThread2);
        t.start();

    }
}

 

使用箭头函数

/**
 * 使用箭头函数(lambda表达式)
 */

public class JianTouHanShu {
    public static void main(String[] args) {
        //箭头函数接口,抽象类,重写方法
        new Thread(
                () -> System.out.println(2)
        ).start();
    }
}

3.实现Callable接口

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

class MyThread3 implements Callable<String>{

    @Override
    public String call() throws Exception {
        return null;
    }
}
public class Test3 {
    public static void main(String[] args) {
        FutureTask<String> futureTask=new FutureTask<>(new MyThread3());
        new Thread(futureTask).start();

    }
}

 

线程的优先级

  概率,比如90%跑主方法,10%跑myThread

 

继承Thread类和实现Runnable接口、实现Callable接口的区别。

    继承Thread:线程代码存放在Thread子类run方法中。

        优势:编写简单,可直接用this.getname()获取当前线程,不必使用Thread.currentThread()方法。

        劣势:已经继承了Thread类,无法再继承其他类。

    实现Runnable:线程代码存放在接口的子类的run方法中。

        优势:避免了单继承的局限性、多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形。

        劣势:比较复杂、访问线程必须使用Thread.currentThread()方法、无返回值。

    实现Callable:

        优势:有返回值、避免了单继承的局限性、多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形。

        劣势:比较复杂、访问线程必须使用Thread.currentThread()方法

 

Java提供两种线程

  用户线程

  守护线程:为用户线程提供服务

Thread t = new Thread();
        t.setDaemon(true);

 

线程的生命周期

1.NEW 线程未被Start()调用执行

2.RUNNABLE,线程正在JVM中被执行,等待来自操作系统的调度

3.BLOCKED,阻塞,不能立即执行,需要挂起等待

4.WAITING,无限期等待,Object类,没有唤醒,一直等待

5.TIMED_WAITING,线程等待一个指定的时间

6.TERMINATED,中止线程的状态

 

等待和阻塞:阻塞因为外部原因,需要等待

 

线程状态管理

1、线程睡眠---sleep:

线程睡眠的原因:线程执行的太快,或需要强制执行到下一个线程。

    线程睡眠的方法(两个):sleep(long millis)在指定的毫秒数内让正在执行的线程休眠。

                sleep(long millis,int nanos)在指定的毫秒数加指定的纳秒数内让正在执行的线程休眠。

2、线程让步---yield:

Thread类提供的一个静态方法,可以让正在执行的线程暂停,但是不会进入阻塞状态,而是直接进入就绪状态。相当于只是将当前线程暂停一下,然后重新进入就绪的线程池中,让线程调度器重新调度一次。也会出现某个线程调用yield方法后暂停,但之后调度器又将其调度出来重新进入到运行状态。

3、线程合并---join:

当B线程执行到了A线程的.join()方法时,B线程就会等待,等A线程都执行完毕,B线程才会执行。

4、停止线程:

开启多线程运行,运行的代码通常是循环结构,只要控制住循环,就可以让run方法结束。

5、设置优先级:

Thread类中提供了优先级的三个常量

MAX_PRIORITY = 10

MIN_PRIORITY = 1

NORM_PRIORITY = 5
------------------------------------------------------ 
ThreadDemo td = new ThreadDemo(); 
Thread t1 = new Thread(td,"设置"); 
t1.priority(9);            
//设置优先级
t1.start();              
//设置完毕

 

线程安全

CPU多核缓存结构

  物理内存:硬盘内存

  cpu缓存为了提高程序运行的性能,

  cpu处理速度最快,内存次之,硬盘最后

  cpu处理数据时,内存运行速度慢,会拖累cpu的速度

  解决这样的问题,cpu有多级缓存(三级缓存)每个cpu都有L1,L2缓存,L3缓存多核公用

  CPU查找数据:CPI->L1->L2->L3->内存->硬盘

  

线程安全的实现

数据不可变

互斥同步,加锁(悲观锁)

非阻塞同步(无锁编程)自旋,用cas实现

无同步方案,多个线程需要共享数据,但这些数据可以在单独的线程中计算

 

线程同步与锁

线程同步:java允许多线程并发控制,当多个线程同时操作一个可共享资源变量时(如对其进行增删改查操作),会导致数据不准确,而且相互之间产生冲突。所以加入同步锁以避免该线程在没有完成操作前被其他线程调用,从而保证该变量的唯一性和准确性。

 

方法一

同步函数:就是用synchronize关键字修饰的方法。因为每个java对象都有一个内置锁,当用synchronize关键字修饰方法时内置锁会保护整个方法,而在调用该方法之前,要先获得内置锁,否则就会处于阻塞状态。

public synchronized void run() {}

 

方法二

同步代码块:就是拥有synchronize关键字修饰的语句块,被该关键字修饰的语句块会自动被加上内置锁,从而实现同步。

public void run() {
        while(true){
            synchronized (this) { //同步代码块
                if(tick>0){
                    try {
                        Thread.sleep(10);//执行中让线程睡眠10毫秒,
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " " + tick--);
                }
            }
        }
    }

 

方法三

lock锁

 

案例:

package duoxiancheng;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class  MyThread_3 implements  Runnable{
    private Integer sum=50;
    @Override
    public synchronized void run() {//synchronized关键字
        while(true){
            if(sum==0){
                break;
            }
            System.out.println(sum);
            sum = sum - 1;
        }

    }
}
class  MyThread_4 implements  Runnable{
    private Integer sum=50;
    @Override
    public void run() {
        while(true){
            synchronized (this) { //同步代码块
                if(sum>0){
                    try {
                        Thread.sleep(10);//执行中让线程睡眠10毫秒,
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " " + sum--);
                }
            }
        }
    }
}
class  MyThread_5 implements  Runnable{
    private Lock lock=new ReentrantLock();
    private Integer sum=50;
    @Override
    public void run() {
        lock.lock();//lock锁
        try {
            while(true){
                if(sum==0){
                    break;
                }
                System.out.println(sum);
                sum = sum - 1;
            }
        } finally {
            lock.unlock();
        }
    }
}
public class Test9 {
    public static void main(String[] args) {
        //synchronized关键字
        MyThread_3 t1=new MyThread_3();
        Thread t11=new Thread(t1);
        Thread t22=new Thread(t1);
        Thread t33=new Thread(t1);
        t11.start();
        t22.start();
        t33.start();

//        //同步代码块
        MyThread_4 t11s=new MyThread_4();
        Thread t111=new Thread(t11s);
        Thread t221=new Thread(t11s);
        Thread t331=new Thread(t11s);
        t111.start();
        t221.start();
        t331.start();

        //lock锁
        MyThread_5 tt1=new MyThread_5();
        Thread tr1=new Thread(tt1);
        Thread tr2=new Thread(tt1);
        Thread tr3=new Thread(tt1);
        tr1.start();
        tr2.start();
        tr3.start();
    }
}

 

线程执行完再执行别的

strictfp

 

死锁

进程A中包含资源A,进程B中包含资源B,A的下一步需要资源B,B的下一步需要资源A,所以它们就互相等待对方占有的资源释放,所以也就产生了一个循环等待死锁。

 

posted @ 2022-08-02 19:04  一只神秘的猫  阅读(37)  评论(0)    收藏  举报