Java多线程基础

Java多线程1 线程创建1.1 继承Thread类1.2 实现Runnable接口1.3 实现Callable接口1.4 静态代理模式1.5 线程创建总结2 线程状态2.1 线程停止2.2 线程休眠2.3 线程礼让2.4 线程强制执行2.5 观测线程状态2.6 线程优先级2.7 守护线程3 线程同步3.1 线程同步机制3.2 并发问题3.3 同步方法与同步块3.4 JUC安全类型集合3.5 死锁3.6 Lock锁4 线程通信4.1 线程通信方法4.2 管程法4.3 信号灯法5 线程池5.1使用线程池
Java多线程
1 线程创建
1.1 继承Thread类
创建线程方式一:继承Thread类
- 继承Thread类,重写run方法,调用start开始线程
xxxxxxxxxx201/*创建线程:继承Thread类,重写run方法,调用start开始线程*/2public class TestThread extends Thread{3    4    public void run() {5        for (int i = 0; i < 20; i++) {6            System.out.println("----线程执行----" + i);7        }8    }9
10    public static void main(String[] args) {11        /*创建线程对象*/12        TestThread testThread = new TestThread();13        /*调用start方法*/14        testThread.start();15
16        for (int i = 0; i < 20; i++) {17            System.out.println("----主线程执行----" + i);18        }19    }20}1.2 实现Runnable接口
创建线程方式二:实现runnable接口
- 实现runnable接口,重写run方法,执行start,开启线程
xxxxxxxxxx201/*实现runnable接口,重写run方法,执行start*/2public class TestThread implements Runnable {3
4    5    public void run() {6        for (int i = 0; i < 20; i++) {7            System.out.println("----线程执行----" + i);8        }9    }10
11    public static void main(String[] args) {12        /*创建Runnable接口的实现类对象*/13        TestThread test = new TestThread();14
15        /*创建线程对象*/16        Thread thread = new Thread(test);17
18        thread.start();19    }20}1.3 实现Callable接口
创建线程方式三:实现Callable接口
- 实现Callable接口,重写call方法,创建执行服务,提交执行,获取结果,关闭服务
xxxxxxxxxx271/*实现Callable接口2* 1.可以定义返回值3* 2.可以抛出异常4*/5public class TestCallable implements Callable<Boolean> {6    7    public Boolean call() {8        System.out.println(Thread.currentThread().getName()+"线程执行");9        return true;10    }11
12    public static void main(String[] args) throws ExecutionException, InterruptedException {13        TestCallable callable1 = new TestCallable();14        TestCallable callable2 = new TestCallable();15
16        /*创建执行服务*/17        ExecutorService ser = Executors.newFixedThreadPool(2);18        /*提交执行*/19        Future<Boolean> result1 = ser.submit(callable1);20        Future<Boolean> result2 = ser.submit(callable2);21        /*获取结果*/22        boolean rs1 = result1.get();23        boolean rs2 = result2.get();24        /*关闭服务*/25        ser.shutdown();26    }27}1.4 静态代理模式
- 代理对象和真实对象需要实现同一个接口,代理对象代理真实角色
- 代理对象可以做很多真实对象做不了的事 ,真实对象专注做自己的事情
xxxxxxxxxx371/*接口*/2interface Marry{3    void HappyMarry();4}5
6/*真实角色*/7class You implements Marry{8    9    public void HappyMarry() {10        System.out.println("Marry");11    }12}13
14/*代理角色*/15class WeddingCompany implements Marry{16
17    private Marry target;18
19    public WeddingCompany(Marry target){20        this.target = target;21    }22
23    24    public void HappyMarry() {25        before();26        this.target.HappyMarry();27        after();28    }29
30    private void after() {31        System.out.println("结婚后,收尾款");32    }33
34    private void before() {35        System.out.println("结婚前,布置现场");36    }37}main:
xxxxxxxxxx91public static void main(String[] args) {2    new Thread(()-> System.out.println("thread")).start();3
4    Marry you = new You();5    WeddingCompany weddingCompany = new WeddingCompany(you);6    weddingCompany.HappyMarry();7    System.out.println("------------");8    you.HappyMarry();9}1.5 线程创建总结
xxxxxxxxxx421public class ThreadNew {2    public static void main(String[] args) {3        //继承Thread4        new MyThread1().start();5        //实现Runnable6        new Thread(new MyThread2()).start();7        //实现Callable8        FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread3());9        new Thread(futureTask).start();10
11        try {12            Integer integer = futureTask.get();13            System.out.println(integer);14        } catch (InterruptedException e) {15            e.printStackTrace();16        } catch (ExecutionException e) {17            e.printStackTrace();18        }19    }20}21
22class MyThread1 extends Thread{23    24    public void run() {25        System.out.println("Thread1 -- extends Thread");26    }27}28
29class MyThread2 implements Runnable{30    31    public void run() {32        System.out.println("Thread2 -- implements Runnable");33    }34}35
36class MyThread3 implements Callable<Integer>{37    38    public Integer call() throws Exception {39        System.out.println("Thread3 -- implements Callable");40        return 100;41    }42}2 线程状态
.png)
- 新建状态: - 使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。 
- 就绪状态: - 当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。 
- 运行状态: - 如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。 
- 阻塞状态: - 如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种: - 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
- 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
- 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
 
- 死亡状态: - 一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。 
2.1 线程停止
- 线程停止: - 线程最好是正常停止
- 需要停止线程设置一个标志位,通过设置标志位,改变标志位停止线程
 
xxxxxxxxxx331/*测试停止2* 1.建议正常停止3* 2.建议使用标志位*/4public class TestStop implements Runnable{5    /*设置一个标志位*/6    private boolean flag = true;7
8    9    public void run() {10        int i = 0;11        while (flag){12            System.out.println("run.......thread"+i++);13        }14    }15
16    public void stop(){17        this.flag = false;18    }19
20    public static void main(String[] args) {21        TestStop testStop = new TestStop();22
23        new Thread(testStop).start();24
25        for (int i = 0; i < 1500; i++) {26            System.out.println("main.......thread"+i);27            if(i == 1000){28                testStop.stop();29                System.out.println("stop......thread");30            }31        }32    }33}2.2 线程休眠
- sleep时间到达之后线程进入就绪状态
- 每个对象都有一个锁,sleep不会释放锁
xxxxxxxxxx11Thread.sleep(200);2.3 线程礼让
- 线程礼让,让当前执行的线程暂停,不阻塞
- 线程从运行状态变为就绪状态
- 礼让不一定成功,根据CPU调度执行
xxxxxxxxxx11Thread.yield();2.4 线程强制执行
- join,等待此线程执行完成才会执行其他线程,其他线程阻塞
xxxxxxxxxx11thread.join();2.5 观测线程状态
xxxxxxxxxx11thread.getState();xxxxxxxxxx291public class TestState {2
3    public static void main(String[] args) throws InterruptedException {4        Thread thread = new Thread(()->{5            for (int i = 0; i < 5; i++) {6                try {7                    Thread.sleep(1000);8                } catch (InterruptedException e) {9                    e.printStackTrace();10                }11                System.out.println("........");12            }13        });14
15        //观察状态16        Thread.State state = thread.getState();17        System.out.println(state);18
19        thread.start();20        state = thread.getState();21        System.out.println(state);22
23        while (state != Thread.State.TERMINATED){24            Thread.sleep(100);25            state = thread.getState();26            System.out.println(state);27        }28    }29}2.6 线程优先级
进入就绪状态的线程,线程调度器按照优先级决定哪个线程先执行
设置 获取优先级
xxxxxxxxxx21t2.setPriority(3);2t2.getPriority()xxxxxxxxxx361public class TestPriority {2
3    public static void main(String[] args) {4        /*主线程优先级*/5        System.out.println(Thread.currentThread().getName() + "-->" + Thread.currentThread().getPriority());6
7        MyPriority myPriority = new MyPriority();8
9        Thread t1 = new Thread(myPriority,"T1");10        Thread t2 = new Thread(myPriority,"T2");11        Thread t3 = new Thread(myPriority,"T3");12        Thread t4 = new Thread(myPriority,"T4");13        Thread t5 = new Thread(myPriority,"T5");14
15        t1.start();16
17        t2.setPriority(3);18        t2.start();19
20        t3.setPriority(5);21        t3.start();22
23        t4.setPriority(6);24        t4.start();25
26        t5.setPriority(Thread.MAX_PRIORITY);27        t5.start();28    }29}30
31class MyPriority implements Runnable{32    33    public void run() {34        System.out.println(Thread.currentThread().getName() + "-->" + Thread.currentThread().getPriority());35    }36}2.7 守护线程
守护进程创建:
xxxxxxxxxx11thread.setDaemon(true);xxxxxxxxxx351/*测试守护线程*/2public class TestDaemon {3    public static void main(String[] args) {4        God god = new God();5        You you = new You();6
7        Thread thread = new Thread(god);8        thread.setDaemon(true);9
10        thread.start();11
12        new Thread(you).start();13    }14}15
16/*God*/17class God implements Runnable{18    19    public void run() {20        while (true){21            System.out.println("god bless you");22        }23    }24}25
26/*you*/27class You implements Runnable{28    29    public void run() {30        for (int i = 0; i < 36500; i++) {31            System.out.println("第" + i + "天");32        }33        System.out.println("Goodbye world");34    }35}3 线程同步
3.1 线程同步机制
并发
同一个对象被多个线程同时操作
线程同步
多个线程访问一个对象,并且线程修改对象的值,这时候就需要线程同步,等待机制,多个同时访问对象的线程进入对象的等待池形成队列,一个线程使用完,下一个线程再使用
3.2 并发问题
例子1:抢票 没有线程同步,此时就会出现多个人抢一张票的情况,产生负数
xxxxxxxxxx251public class Unsafe implements Runnable{2    private int tickNums = 10;3
4    5    public void run() {6        while (tickNums > 0) {7
8            try {9                Thread.sleep(200);10            } catch (InterruptedException e) {11                e.printStackTrace();12            }13
14            System.out.println(Thread.currentThread().getName() + "拿到了第" + tickNums-- + "张票");15        }16    }17
18    public static void main(String[] args) {19        Unsafe thread = new Unsafe();20
21        new Thread(thread,"小明").start();22        new Thread(thread,"老师").start();23        new Thread(thread,"黄牛").start();24    }25}例子2:多线程插入List,出现重复插入导致数据缺失
xxxxxxxxxx181public class UnsafeList {2    public static void main(String[] args) {3        List<String> List = new ArrayList<>();4        for (int i = 0; i < 10000; i++) {5            new Thread(()->{6                List.add(Thread.currentThread().getName());7            }).start();8        }9
10        try {11            Thread.sleep(3000);12        } catch (InterruptedException e) {13            e.printStackTrace();14        }15
16        System.out.println(List.size());17    }18}3.3 同步方法与同步块
同步方法:public synchronized void method()
- synchronized 方法控制对对象的访问,每个对象对应一把锁,每个synchronized 方法都必须获得调用该方法的对象的锁才能执行,方法开始执行,就会独占该锁,直到执行结束才会释放锁,阻塞的线程才能获取这个锁
xxxxxxxxxx321public class TestSynchronized implements Runnable{2    private int tickNums = 10;3    boolean flag = true;4
5    6    public void run() {7        while (flag) {8            try {9                buy();10            } catch (InterruptedException e) {11                e.printStackTrace();12            }13        }14    }15
16    public synchronized void buy() throws InterruptedException{17        if (tickNums <= 0) {18            flag = false;19            return;20        }21        Thread.sleep(100);22        System.out.println(Thread.currentThread().getName() + "拿到了第" + tickNums-- + "张票");23    }24
25    public static void main(String[] args) {26        TestSynchronized thread = new TestSynchronized();27
28        new Thread(thread,"小明").start();29        new Thread(thread,"老师").start();30        new Thread(thread,"黄牛").start();31    }32}同步块:synchronized(obj){}
obj为同步监视器
- Obj为获取锁的对象,执行同步块时会获取Obj的锁,进行线程同步
- 同步方法默认同步监视器为this,或者为class
xxxxxxxxxx201public class TestSynList {2    public static void main(String[] args) {3        List<String> List = new ArrayList<>();4        for (int i = 0; i < 10000; i++) {5            new Thread(()->{6                synchronized (List){7                    List.add(Thread.currentThread().getName());8                }9            }).start();10        }11
12        try {13            Thread.sleep(3000);14        } catch (InterruptedException e) {15            e.printStackTrace();16        }17
18        System.out.println(List.size());19    }20}3.4 JUC安全类型集合
CopyOnWriteArrayList
类本身能实现线程同步,直接使用
xxxxxxxxxx181public class TestJUC {2    public static void main(String[] args) {3        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();4        for (int i = 0; i < 10000; i++) {5            new Thread(()->{6               list.add(Thread.currentThread().getName());7            }).start();8        }9
10        try {11            Thread.sleep(3000);12        } catch (InterruptedException e) {13            e.printStackTrace();14        }15
16        System.out.println(list.size());17    }18}3.5 死锁
死锁的四个必要条件
- 1.互斥条件:一个资源只能被一个进程使用
- 2.请求与保持:一个进程因请求资源而阻塞时,对已有的资源保持不是放
- 3.不剥夺条件:进程已获得的资源,在未使用完之前不进行剥夺
- 4.循环等待:若干进程之间形成头尾相连的循环等待资源的关系
xxxxxxxxxx611/*死锁*/2public class DeadLock {3    public static void main(String[] args) {4        Makeup q1 = new Makeup(0,"A");5        Makeup q2 = new Makeup(1,"B");6
7        q1.start();8        q2.start();9    }10}11
12class Lipstick{13
14}15
16class Mirror{17
18}19
20class Makeup extends Thread{21
22    static Lipstick lipstick = new Lipstick();23    static Mirror mirror = new Mirror();24
25    private int choice;26    private String Name;27
28    Makeup(int choice,String name){29        this.choice = choice;30        this.Name = name;31    }32
33    34    public void run() {35        try {36            makeup();37        } catch (InterruptedException e) {38            e.printStackTrace();39        }40    }41
42    private void makeup() throws InterruptedException {43        if (choice == 0) {44            synchronized (lipstick){45                System.out.println(Name + "获得口红锁");46                Thread.sleep(1000);47                synchronized (mirror){48                    System.out.println(Name + "获得镜子锁");49                }50            }51        }else {52            synchronized (mirror){53                System.out.println(Name + "获得镜子锁");54                Thread.sleep(2000);55                synchronized (lipstick){56                    System.out.println(Name + "获得口红锁");57                }58            }59        }60    }61}3.6 Lock锁
ReentrantLock类实现了Lock,可以显式加锁与释放锁
xxxxxxxxxx411/*测试Lock锁*/2public class Lock {3    public static void main(String[] args) {4        TestLock L1 = new TestLock();5
6        new Thread(L1,"L1").start();7        new Thread(L1,"L2").start();8        new Thread(L1,"L3").start();9    }10}11
12
13class TestLock implements Runnable{14
15    private int tickNum = 10;16    private boolean flag= true;17
18    /*定义lock锁*/19    private ReentrantLock lock = new ReentrantLock();20
21    22    public void run() {23        while (flag){24            try {25                lock.lock();26                buy();27            }finally {28                lock.unlock();29            }30        }31    }32
33    public void buy(){34        if (tickNum <= 0) {35            flag = false;36            return;37        }38
39        System.out.println(Thread.currentThread().getName() + "  " +tickNum--);40    }41}4 线程通信
4.1 线程通信方法
wait()
- 线程会一直等待,知道其他线程通知,与sleep不同,会释放锁
- wait可以加参数毫秒,表示指定等待的时间
notify()
- 唤醒一个处于的等待状态的线程
notifyAll()
- 唤醒同一个对象所有调用wait()方法的线程
4.2 管程法
生产者/消费者模型
- 生产者:负责产生数据的模块
- 消费者:负责处理数据的模块
- 缓冲区:生产者将生产好的数据放入缓冲区,消费者从缓冲区拿数据
xxxxxxxxxx1041/*生产者,消费者,产品,缓冲区*/2public class TestPC {3    public static void main(String[] args) {4        SynContainer container = new SynContainer();5
6        new Producer(container).start();7        new Consumer(container).start();8    }9}10
11class Producer extends Thread{12    SynContainer container;13
14    public Producer(SynContainer container) {15        this.container = container;16    }17
18    /*生产*/19    20    public void run() {21        for (int i = 0; i < 100; i++) {22            System.out.println("生产了第"+i+"只鸡");23            container.push(new Chicken(i));24        }25    }26}27
28class Consumer extends Thread{29    SynContainer container;30
31    public Consumer(SynContainer container) {32        this.container = container;33    }34
35    /*生产*/36    37    public void run() {38        for (int i = 0; i < 100; i++) {39            Chicken chicken = container.pop();40            System.out.println("吃了第"+chicken.getID()+"只鸡");41        }42    }43}44
45class Chicken{46    private int ID;47
48    public Chicken(int ID) {49        this.ID = ID;50    }51
52    public int getID() {53        return ID;54    }55}56
57class SynContainer{58    Chicken[] chickens = new Chicken[10];59    int count = 0;60
61    /*生产者放入产品*/62    public synchronized void push(Chicken chicken){63        /*容器满了,等待消费*/64        if (count == chickens.length) {65            try {66                /*等待消费*/67                this.wait();68            } catch (InterruptedException e) {69                e.printStackTrace();70            }71        }72
73        /*如果容器没满,放入产品*/74        chickens[count] = chicken;75        count++;76
77        /*通知消费者消费*/78        this.notifyAll();79    }80
81    /*消费者取出产品*/82    public  synchronized Chicken pop(){83        /*判断是否存在产品*/84        if (count == 0) {85            try {86                /*等待生产*/87                this.wait();88            } catch (InterruptedException e) {89                e.printStackTrace();90            }91        }92
93        /*消费者消费*/94        count--;95        Chicken chicken = chickens[count];96        chickens[count] = null;97
98        /*通知生产者生产*/99        this.notifyAll();100
101        return chicken;102    }103
104}4.3 信号灯法
通过一个标志位来判断生产是否完成,消费是否完成
xxxxxxxxxx921/*信号量*/2public class TestPC2 {3    public static void main(String[] args) {4        TV tv = new TV();5
6        new Player(tv).start();7        new Watcher(tv).start();8    }9}10
11/*生产者-->演员*/12class Player extends Thread{13    private TV tv;14
15    public Player(TV tv){16        this.tv = tv;17    }18
19    20    public void run() {21        for (int i = 0; i < 20; i++) {22            if (i%2 == 0){23                tv.play("你所热爱的就是你的生活");24            }else{25                tv.play("柠檬什么时候熟");26            }27        }28    }29}30
31/*消费者-->观众*/32class Watcher extends Thread{33    private TV tv;34    35    public Watcher(TV tv){36        this.tv = tv;37    }38
39    40    public void run() {41        for (int i = 0; i < 20; i++) {42            tv.watch();43        }44    }45}46
47/*产品-->节目*/48class TV{49    /*演员表演,观众等待*/50    /*观众观看,演员等待*/51    String voice;52    boolean flag = true;53
54    /*表演*/55    public synchronized void play(String voice){56
57        if (!flag){58            try {59                this.wait();60            } catch (InterruptedException e) {61                e.printStackTrace();62            }63        }64
65        System.out.println("演员表演了:"+voice);66
67        /*通知观众观看*/68        this.notifyAll();69        this.voice = voice;70        this.flag = !this.flag;71    }72
73
74    /*观看*/75    public synchronized void watch(){76
77        if (flag){78            try {79                this.wait();80            }catch (InterruptedException e) {81                e.printStackTrace();82            }83        }84        System.out.println("观众观看了:"+voice);85        86        /*通知演员表演*/87        this.notifyAll();88        this.voice = "";89        this.flag = !this.flag;90    }91
92}5 线程池
提前创建好多个线程,放入线程池,直接获取使用,放回池内
- 提高响应速度
- 降低资源消耗
- 便于管理线程
5.1使用线程池
271/*测试线程池*/2public class TestThreadPool {3
4    public static void main(String[] args) {5        /*1.创建服务,创建线程池*/6        ExecutorService service = Executors.newFixedThreadPool(10);7
8        /*执行*/9        service.execute(new MyThread());10        service.execute(new MyThread());11        service.execute(new MyThread());12        service.execute(new MyThread());13
14        /*2.关闭链接*/15        service.shutdown();16    }17}18
19
20class MyThread implements Runnable{21    22    public void run() {23        for (int i = 0; i < 10; i++) {24            System.out.println(Thread.currentThread().getName()+" "+i);25        }26    }27}posted on 2021-12-03 18:26 Egoistic_Flowers 阅读(39) 评论(0) 收藏 举报
 
 
         
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号