Java线程总结1

一、线程与进程

1.进程:指一个内存中运行的应用程序,每个进程都有一个独立的内存空间;
2.线程:指进程的一个执行路径,多个线程之间可以通信,自由切换,并发执行;一个线程最少有一个线程;
3.线程分为用户线程和守护线程;
4.线程调度:
(1)分时调度:所有线程轮流使用CPU,平均使用时间;
(2)抢占式调度:优先让优先级高的线程使用CPU,优先级相同,则随机选择;Java为抢占式调度。

二、同步与异步

(1)同步:线程安全
排队执行,效率低但安全;
(2)异步:线程不安全
同时执行,效率高但不安全。

三、并发和并行

(1)并发:
指在同一时间段内发生;
例如在一分钟内的交易数量等;
(2)并行:
指在同一时刻发生;

四、创建线程:

1.继承Thread;
(1)在继承的类中,写run( )方法,描述线程要做的功能;
(2)当需要开启一个新线程来执行run( )中的内容,则在调用的方法中,创建(1)中的类的对象,然后使用start( )方法来开启一个新线程,然后执行run( )中的内容;

2.实现接口Runnable;
(1)过程:

   1.创建一个实现了Runnable接口的类1,同时实现了抽象方法run( );
   2.在调用的方法中,创建类1的对象,在创建Thread类的对象的构造方法的参数中,传入类1的对象;
   3.然后Thread类的对象使用start( )方法开启一个新线程来执行类1中的run( )。
public class Thread1 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new MyRunnable());
        t1.start();
        for(int i = 0;i<=5;i++){
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
        //打一个中断标记;
        t1.interrupt();

    }

    static class MyRunnable implements Runnable{
        @Override
        public void run() {
            for(int i = 0;i<=10;i++){
                System.out.println(Thread.currentThread().getName()+":"+i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("发现线程中断标记,终止线程");
                    return;
                }
            }
        }
    }
}

(2)优势:

1.灵活性强,在给Thread类的构造方法传参时,可以传多种,更适合实现多线程执行多任务,传参可以理解为分配任务;
2.可以避免单继承的局限性,因为Java中不允许多继承,但支持多实现,可以实现多个接口;
3.任务和线程的创建时分离的,提高了程序的健壮性;
4.Runnable,可在线程池中使用;

五、Thread类

1.四种常用构造方法;
Thread(String name):name为线程名称;

2.三个静态常量:优先级设置;
MAX_PRIORITY,最高
MIN_PRIORITY,最小
NORM__PRIORITY,默认

3.常用方法:
(1)start( );
结束线程,应使用变量标记法,不能使用过时方法stop( ),因为在流中会导致无法正常关闭流。
(2)getPriority 和 setPriority(优先级静态常量);
(3)getId( )
(4)getName 和 setName(String)
(5)static Thread currentThread( ):
Thread类的静态方法,获得当前线程对象;
(6)static void sleep(int 毫秒数):
Thread类的静态方法,线程休眠;
(7)setDaemon(boolean):设置守护线程;
参数为true则设为守护线程;
线程分为 daemon线程(即守护线程)和用户线程;
直接创建的都是用户线程;

守护线程:当最后一个用户线程结束,则所有守护线程结束,代码如下;

public class Thread2 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Thread1.MyRunnable(),"守护线程");
        //设置为守护线程;
        t1.setDaemon(true);
        t1.start();

        for(int i = 0;i<=5;i++){
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+":"+i);
        }

    }

    static class MyRunnable implements Runnable{
        @Override
        public void run() {
            for(int i = 0;i<=10;i++){
                System.out.println(Thread.currentThread().getName()+":"+i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }
    }
}

六、线程阻塞:

所有比较耗费时间的操作都叫线程阻塞;
包括但不限于:IO文件操作,等待用户输入,等。

七、线程中断:

1.使用interrupt()方法,进行中断标记;
在线程中使用Wait(),sleep(…),等方法后会抛出InterruptedExprection异常,在sleep的try…catch块中使用return结束run( )方法,从而结束线程。

public class Thread1 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new MyRunnable());
        t1.start();
        for(int i = 0;i<=5;i++){
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
        //打一个中断标记;
        t1.interrupt();

    }

    static class MyRunnable implements Runnable{
        @Override
        public void run() {
            for(int i = 0;i<=10;i++){
                System.out.println(Thread.currentThread().getName()+":"+i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("发现线程中断标记,终止线程");
                    return;
                }
            }
        }
    }
}

八、线程安全1同步代码块

synchronized(锁对象)
1.锁对象可以是任何对象;
2.要保证线程安全和同步,要使用同一个锁对象;

public class Thread3 {
    public static void main(String[] args) {
        MyRunnable m1 = new MyRunnable();
        new Thread(m1).start();
        new Thread(m1).start();
        new Thread(m1).start();

    }

    static class MyRunnable implements Runnable{
        private int ticket = 18;
        private Object o = new Object();
        @Override
        public void run() {
           while(true){
               //线程安全1,线程安全代码块;
               synchronized (o){
                   if(ticket>0){
                       ticket--;
                       System.out.println(Thread.currentThread().getName()+"出票成功,余票:"+ticket);
                       try {
                           Thread.sleep(500);
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }else{
                       break;
                   }
               }

           }
        }
    }
}

九、线程安全2同步方法:

1.加synchronized修饰方法;
2.方法中的锁对象为:
当是static方法,锁对象为:类名.class
不是static方法时,锁对象:this
3.当同时出现同步代码块和同步方法时,若锁对象相同,则每次只能执行其中一个;
4.当有多个相同static修饰情况的synchronized方法时,则每次只执行其中一个;

public class Thread4 {
    public static void main(String[] args) {
        MyRunnable m1 = new MyRunnable();
        new Thread(m1).start();
        new Thread(m1).start();
        new Thread(m1).start();

    }

    static int[] asd(int[] a){
        int[] b = new int[1];
        b[1] = a.length;
        return b;
    }

    static class MyRunnable implements Runnable{
        private int ticket = 18;
        private Object o = new Object();
        @Override
        public void run() {
            while(true){
              if(!isNot()){
                  break;
              }
            }
        }
        //线程安全2,安全方法修饰
        public synchronized boolean isNot(){
            if(ticket>0){
                ticket--;
                System.out.println(Thread.currentThread().getName()+"出票成功,余票:"+ticket);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return true;
            }else{
                return false;
            }
        }
    }
}

十、线程安全3显示锁:

1.抽象类Lock的子类,ReentrantLock;
Lock l = new ReentrantLock( );
2.常用方法:
加锁:lock( ); 解锁:unlock( )

十一、公平锁

1.公平锁:
先来先到,按照代码从上到下的顺序执行;
在显示锁实例化时,添加true参数;
Lock l = new ReentrantLock(true);

2.Java中的三种锁机制默认都是非公平锁;

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

public class Thread5 {
    //Lock,显示锁和公平锁
    public static void main(String[] args) {
        MyThread m1 = new MyThread();
        new Thread(m1).start();
        new Thread(m1).start();
        new Thread(m1).start();

    }

    static class MyThread implements Runnable{
        private int ticket = 18;
        //公平锁
        Lock l1 = new ReentrantLock(true);
        @Override
        public void run() {
            while(true){
                l1.lock();
                if(ticket>0){
                    ticket--;
                    System.out.println(Thread.currentThread().getName()+"出票成功,余票:"+ticket);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    l1.unlock();
                }else{
                    l1.unlock();
                    break;
                }

            }
        }
    }
}

十二、线程死锁

1.死锁:环环相扣,两个锁互相等待对方解锁才能继续执行;
2.避免方法:当有可能出现锁的情况时,只允许又一个锁即可;

public class Thread6 {
    //死锁
    public static void main(String[] args) {
        Police p = new Police();
        Crime c = new Crime();
        Mythread m1 = new Mythread(p,c);
        new Thread(m1).start();

        c.say(p);

    }

    static class Mythread implements Runnable{
        private Police p;
        private Crime c;

        public Mythread(Police p, Crime c) {
            this.p = p;
            this.c = c;
        }

        @Override
        public void run() {
            p.say(c);
        }
    }

    static class Police{
        public synchronized void say(Crime c){
            System.out.println("警察:放了人质,我就放了你");
            c.respond();
        }

        public synchronized void respond(){
            System.out.println("人质救出,罪犯跑了");
        }
    }

    static class Crime{
        public synchronized void say(Police p){
            System.out.println("罪犯:放了我,就放了人质");
            p.respond();
        }

        public synchronized void respond(){
            System.out.println("罪犯跑了,人质也放了");
        }
    }
}

十三、多线程通信问题:生产者和消费者

1.主要方法:
使用Object类的wait( ) 和 notifyAll( );
2.也可以使用公平锁来解决;

public class Thread8 {
    //多线程通信
    //生产者和消费者
    public static void main(String[] args) {
        Food f1 = new Food();
        Cooker c = new Cooker(f1);
        Waiter w = new Waiter(f1);
        c.start();
        w.start();

    }

    static class Cooker extends Thread{
        private Food f;
        public Cooker(Food f) {
            this.f = f;
        }

        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                if (i % 2 == 0) {
                    f.setAll("牛排", "咸香");
                } else {
                    f.setAll("螺蛳粉", "恶臭");
                }

            }

        }
    }

    static class Waiter extends Thread{
        private Food f;

        public Waiter(Food f) {
            this.f = f;
        }

        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                f.get();

            }

        }
    }

    static class Food{
        private String name;
        private String taste;
        private boolean flag = true;

        public synchronized void setAll(String n, String t){
            if(flag){
                this.name = n;
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                this.taste = t;
                flag = false;
                this.notifyAll();
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }

        }

        public synchronized void get(){
            if(!flag){
                System.out.println("服务员端走的菜的名称是:"+name+",口味是:"+taste);
                flag = true;
                this.notifyAll();
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }

    }
}

十四、线程的六种状态

在这里插入图片描述

十五、带返回值的线程:CallAble

1.先实现接口CallAbale<T>,实现方法<T> call( );
2.再创建类FutureTask<T>,传入第一步创建的CallAble对象;
3.new Thread(FutureTask对象);

其中在FutureTask对象有以下方法,实现主线程等待CallAble线程先执行:
1.常用方法:
IsDone( ),是否结束;
cancel(Boolean ),提前结束该线程;
get( ),获取call()的返回值,主线程会等待CallAble线程先执行,得到返回值后再继续执行主线程;

2.上述方法都会导致主线程等待。

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

public class Thread7 {
    //CallAble线程
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCallable m1 = new MyCallable();
        FutureTask<Integer> myCallableFutureTask = new FutureTask<Integer>(m1);
        new Thread(myCallableFutureTask).start();

        System.out.println(myCallableFutureTask.get());


    }

    static class MyCallable implements Callable<Integer> {
        private int age = 18;
        @Override
        public Integer call() throws Exception {
            return age;
        }
    }
}

十六、线程池:

ExecutorSerivce类。
因为创建和关闭线程的时间相比执行时间多得多,所以若多次创建关闭会浪费时间,所以创建大量线程时,使用线程池。
1.包含多个线程的容器;
2.结构上分为:线程数组和任务列表;
3.线程数组分为定长数组、可变数组;对于定长数组,任务较多时会出现排队的情况;且数组中靠前的线程优先执行任务;
4.线程池共分为以下四种;

十七、缓存线程池

  1. 不定长线程池;

  2. 当任务数量过多时,会自动对线程数组扩容,不会出现任务过多而排队的情况;当任务数量较少,会自动删除空闲的线程;
    ExecutorSerivce e = Executors. newCachedThreadPool( );

    e.execute(new Runable);

  3. 注意:当有空闲线程时,会使用已有线程,不会新建线程,例子如下:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Pool1 {
    //缓存线程池
    public static void main(String[] args) {
        ExecutorService e1 = Executors.newCachedThreadPool();
        e1.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"111111");
            }
        });

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

        e1.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"222222");
            }
        });

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

        e1.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"333333");
            }
        });

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


}

十八、定长线程池

线程数量不变;
当有过多任务时,会出现排队的情况;
ExecutorSerivce e = Executors. newFixedThreadPool( 10 );
e.execute(new Runnable);

十九、单线程线程池

只有一个线程;
场景:当任务要求排队执行时;
ExecutorSerivce e = Executors. newSingleThreadPool();
e.execute(new Runnable);

二十、周期 定长 线程池

ScheduledExecutorSerivce e=Executors. newScheduledThreadPool(2);

1.定时执行一次:schedule( … ,…, … ),三个参数:
e.schedule(new Runnable, int 时长数字,TimeUnit.时间单位);
参数3是指定参数2的时间单位;

  1. scheduleAtFixedRate;四个参数:
    e.scheduleAtFixedRate(new Runnable, 延迟时长(第一次执行在什么时间之后),周期时长,TimeUnit.时间单位);
    参数4是指定参数3的时间单位;

二十一、Lambda表达式:

将匿名内部类的实现,只保留对应抽象方法的参数和方法体部分,参数和方法体之间使用 -> 相连;

public class Lambda {
    public static void main(String[] args) {
        //正常匿名内部类格式
        ShowBook(new Book() {
            @Override
            public int page(int i) {
                return i;
            }
        },100);

        //Lambda格式
        ShowBook((int i) -> {return i;},200);
    }

    static void ShowBook(Book b,int x){
        int page = b.page(x);
        System.out.println(page);
    }

    static interface Book{
        int page(int i);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值